Skip to content

fix(backend): make multisig (address, chainId) the real account key#254

Merged
gianalarcon merged 1 commit into
developfrom
fix/backend-account-address-unique-per-chain
May 13, 2026
Merged

fix(backend): make multisig (address, chainId) the real account key#254
gianalarcon merged 1 commit into
developfrom
fix/backend-account-address-unique-per-chain

Conversation

@Huygon764
Copy link
Copy Markdown
Contributor

Hot-fix production: "Can't create base account".

My assumption is it could create same address in both chain, but previously we only have 1 chain so I set @unique on address, so maybe it create address_1 in horizen, and on base it also create same address_1, so it can't create on db because the contraint.

Solution is change constraint from unique address to unique (address + chain_id)

Contract addresses derive from CREATE = keccak256(rlp(sender, nonce)) and do
not include chainId, so the same relayer wallet produces identical addresses
on Horizen and Base when nonces align. The previous `accounts.address @unique`
global constraint blocked legitimate multi-chain deployments and also let
guards mismatch members across chains.

Schema: drop the global address unique, add composite (address, chainId) on
accounts; add chain_id to transactions and reserved_nonces and replace the
foreign key, unique, and indexes with composite versions. Migration backfills
chain_id from the parent account row before promoting NOT NULL and refuses to
run if any orphan transaction is found.

Code: route every account lookup through (address, chainId) — guards require a
chainId query param, services use the composite key, x402 keeps a findFirst
since it is chain-scoped to Base. Frontend hooks and api services pass the
current account's chainId everywhere they previously sent only the address.
@gianalarcon gianalarcon merged commit bc42156 into develop May 13, 2026
1 of 2 checks passed
Huygon764 added a commit that referenced this pull request May 13, 2026
* fix(backend): make multisig (address, chainId) the real account key (#254)

Contract addresses derive from CREATE = keccak256(rlp(sender, nonce)) and do
not include chainId, so the same relayer wallet produces identical addresses
on Horizen and Base when nonces align. The previous `accounts.address @unique`
global constraint blocked legitimate multi-chain deployments and also let
guards mismatch members across chains.

Schema: drop the global address unique, add composite (address, chainId) on
accounts; add chain_id to transactions and reserved_nonces and replace the
foreign key, unique, and indexes with composite versions. Migration backfills
chain_id from the parent account row before promoting NOT NULL and refuses to
run if any orphan transaction is found.

Code: route every account lookup through (address, chainId) — guards require a
chainId query param, services use the composite key, x402 keeps a findFirst
since it is chain-scoped to Base. Frontend hooks and api services pass the
current account's chainId everywhere they previously sent only the address.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants