Smart Contract Accounts (Gnosis Safe)
Use a Gnosis Safe (or similar smart-contract wallet) as the owner of your Synthetix master account. The Safe holds custody onchain; a separate manager EOA signs trading API requests because the Safe cannot produce EIP-712 signatures directly.
This is different from sub-account delegation (addDelegatedSigner), which grants session or delegate permissions on a specific subaccount. A manager is an account-level role granted onchain.
Roles
| Role | Wallet type | How it is granted | Typical use |
|---|---|---|---|
| Owner | Safe (smart contract) | First deposit from the Safe | Custody, onchain deposits |
| Manager | EOA | Safe calls PermissionsRegistry.addManager | Sign API requests for account admin actions |
| Delegate / session | EOA | Owner, manager, or sub-account delegate calls addDelegatedSigner | On-exchange trading keys |
End-to-end flow
1. Deposit from the Safe
Deposit collateral from the Safe to SynthetixDepositContract using a standard multisig transaction. See Deposits & Account Creation.
The Safe address becomes the owner wallet for the master account (sub_accounts.wallet_address). Query IDs with getSubAccountIds.
2. Assign a manager onchain
The Safe must grant a normal EOA permission to act on its behalf:
// Called by the Safe (msg.sender = Safe address)
IPermissionsRegistry(PERMISSIONS_REGISTRY).addManager(managerEOA);| Network | PermissionsRegistry (Proxy) |
|---|---|
| Mainnet | 0x45F91031b33Da2585932c8f1cdFF0faa6cD329ae |
The relayer indexes PermissionGranted / PermissionRevoked events; the backend updates manager authorization within a few blocks. To revoke: revokeManager(managerEOA).
3. Operate the account with the manager EOA
The manager signs EIP-712 requests with its own private key (same domain and flow as EIP-712 Signing). Use the target subaccount's subAccountId in each signed request.
| Action | Notes |
|---|---|
| withdrawCollateral | destination must be the owner Safe address |
| transferCollateral | Source and destination must belong to the same owner wallet (managers cannot transfer across different Safes) |
| createSubaccount | Creates subaccounts under the Safe owner; send params.subAccountId as an existing managed ID — EIP-712 signs it as masterSubAccountId (see endpoint docs) |
| updateSubAccountName | Rename subaccounts |
| removeAllDelegatedSigners | Clear all delegates on a subaccount |
voluntaryCollateralExchange | Collateral conversion under owner account |
| addDelegatedSigner / remove | Manager tier equals owner for delegation admin |
| Action | Why |
|---|---|
placeOrders, placeIsolatedOrder, cancelOrders, cancelAllOrders, modifyOrder, modifyOrderBatch, scheduleCancel | Requires sub-account session (or delegate) delegation — assign via addDelegatedSigner |
| Withdraw to an arbitrary address | Blocked — managers may only withdraw to the owner wallet |
4. Enable on-exchange trading (optional)
To trade on Synthetix from an EOA without the Safe signing each order:
- The manager EOA calls
addDelegatedSignerwithpermissions: ["session"]for a trading key EOA on the target subaccount (after onchainaddManager). - The session EOA signs
placeOrdersand related trading actions.
Alternatively, the manager EOA can hold session delegation on the subaccount and sign trades directly.
5. Discover managed workspaces
If your wallet is a pure manager (no owned accounts), the default getSubAccountIds response is an empty array. Use this bootstrap sequence:
- Call unsigned
getSubAccountIdswithincludeDelegations: trueand readmanagedSubAccountIds. Retry after the onchainaddManagertransaction confirms if the list is still empty. - Pick one managed ID and use it as
subAccountIdwhen signing trade requests (including getSubAccounts). - Call signed
getSubAccounts. The response has two complementary views:subAccounts— all sibling subaccounts under the same master as the authenticated ID (for a manager signing with a Safe subaccount ID, this is that Safe's workspace).managedAccounts— every owner wallet this manager can access, grouped by owner address (useful when you manage multiple Safes in one call).
For a single Safe, subAccounts and managedAccounts[safeAddress] overlap; use managedSubAccountIds only to pick an ID to authenticate, not as a substitute for signed reads.
managedSubAccountIds is discovery-only; signed trade calls always require a concrete subAccountId in the EIP-712 envelope.
Example: manager withdrawal to Safe
{
"params": {
"action": "withdrawCollateral",
"subAccountId": "1867542890123456789",
"symbol": "USDT",
"amount": "1000.0",
"destination": "0xYourSafeAddress..."
},
"nonce": 1704067200000,
"signature": { "...": "signed by manager EOA" },
"expiresAfter": 1704067300
}If destination is not the Safe owner address, the API returns HTTP 403: "Managers may only withdraw to the owner's wallet address".
Related
- Deposits & Account Creation
- Withdraw Collateral
- Add Delegated Signer — sub-account trading keys only
- Get Subaccounts
