Context
Currently all credit retirements default to "US" jurisdiction (config.defaultJurisdiction in src/config.ts:95). This applies to MsgRetire, MsgBuyDirect, and MsgSend — all three on-chain message types include a jurisdiction field (ISO 3166-1 alpha-2 country code).
The MCP tool retire_credits accepts an optional jurisdiction parameter that overrides the default, but subscribers have no way to set their jurisdiction — all scheduled retirements use the hardcoded default.
Raised by Marie — retirement records on-chain should accurately reflect where the beneficiary is located.
Proposed Solution
1. Add country field to users table
ALTER TABLE users ADD COLUMN country TEXT; -- ISO 3166-1 alpha-2
2. Allow setting country at multiple touchpoints
- Signup flow (optional field) — country dropdown during subscription checkout
- Dashboard settings — editable from profile/settings page after signup
- Stripe sync — pull
customer.address.country from Stripe if available (Stripe collects billing address for tax purposes). Could sync on customer.updated webhook or on first login after subscription.
3. Jurisdiction resolution order
When retiring credits, resolve jurisdiction in this priority:
- Explicit
jurisdiction param (MCP tool callers)
user.country (if set in profile)
- Stripe customer country (if available)
config.defaultJurisdiction ("US" fallback)
4. Affected code paths
| File |
What changes |
src/server/db.ts |
Add country column to users table |
src/server/dashboard.ts |
Add country field to settings/profile UI |
src/server/routes.ts |
Accept country during checkout flow |
src/services/retirement.ts |
Use user's country in executeRetirement() |
src/services/retire-subscriber.ts |
Look up subscriber's country for scheduled retirements |
src/services/pool.ts |
Same — use subscriber country instead of global default |
src/config.ts |
Keep defaultJurisdiction as final fallback |
5. On-chain fields for reference
All three retirement message types include jurisdiction:
- MsgBuyDirect:
orders[].retirementJurisdiction
- MsgRetire:
jurisdiction
- MsgSend:
credits[].retirementJurisdiction
Format is ISO 3166-1 alpha-2 (e.g., "US", "CO", "DE", "KE"). Optionally supports subnational: "US-WA", "CO-ANT".
Design Notes (from Marie)
- Keep it optional — don't add friction to signup
- Let users customize it later from their dashboard
- Stripe billing address is a good automatic source if we can get it
- The goal is accuracy on-chain, not gatekeeping
Context
Currently all credit retirements default to
"US"jurisdiction (config.defaultJurisdictioninsrc/config.ts:95). This applies to MsgRetire, MsgBuyDirect, and MsgSend — all three on-chain message types include ajurisdictionfield (ISO 3166-1 alpha-2 country code).The MCP tool
retire_creditsaccepts an optionaljurisdictionparameter that overrides the default, but subscribers have no way to set their jurisdiction — all scheduled retirements use the hardcoded default.Raised by Marie — retirement records on-chain should accurately reflect where the beneficiary is located.
Proposed Solution
1. Add
countryfield to users table2. Allow setting country at multiple touchpoints
customer.address.countryfrom Stripe if available (Stripe collects billing address for tax purposes). Could sync oncustomer.updatedwebhook or on first login after subscription.3. Jurisdiction resolution order
When retiring credits, resolve jurisdiction in this priority:
jurisdictionparam (MCP tool callers)user.country(if set in profile)config.defaultJurisdiction("US" fallback)4. Affected code paths
src/server/db.tscountrycolumn to users tablesrc/server/dashboard.tssrc/server/routes.tssrc/services/retirement.tsexecuteRetirement()src/services/retire-subscriber.tssrc/services/pool.tssrc/config.tsdefaultJurisdictionas final fallback5. On-chain fields for reference
All three retirement message types include jurisdiction:
orders[].retirementJurisdictionjurisdictioncredits[].retirementJurisdictionFormat is ISO 3166-1 alpha-2 (e.g., "US", "CO", "DE", "KE"). Optionally supports subnational: "US-WA", "CO-ANT".
Design Notes (from Marie)