Technical Reference
A condensed walkthrough of the on-chain contract and the EIP-712 payloads the frontend signs. Everything below maps to verified on-chain source — Arbiscan links are included as the source of truth.
All signed payloads use EIP-712 typed data, so signatures are bound to a specific contract and are human-readable in the wallet — never opaque blobs.
Deployments
The platform currently runs on Arbitrum. The same vault address is deployed to both networks (a deterministic UUPS proxy deployment).
| Network | Chain ID | Vault address |
|---|---|---|
| Arbitrum Sepolia (testnet) | 421614 | 0xBA5924D1CbA9618cfF1e5f58C36268Ba04E21A25 |
| Arbitrum (mainnet) | 42161 | 0xBA5924D1CbA9618cfF1e5f58C36268Ba04E21A25 |
Example testnet asset: USDC at 0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d.
The vault is a UUPS upgradeable proxy (ERC-1967) with role-based admin control and an emergency pause. The withdrawal payout contract is exposed by the vault as paymentManager() — that is the verifying contract for withdraw signatures.
Delegated session keys
A fresh EVM keypair is generated locally on first login. It is stored in browser localStorage with a TTL matching the expiresAt in the Login payload.
The delegated key:
- Can sign trading actions (orders, cancels, TP/SL updates, leverage and margin changes).
- Cannot move funds. Deposits and withdrawals always require your main wallet.
- Is rotated automatically on logout, on error, or after its TTL expires.
EIP-712 — Login
Authenticates you and authorizes the delegated session signer in a single popup.
| Field | Type | Description |
|---|---|---|
walletAddress | address | Your main wallet (the authorizer). |
agentAddress | address | The delegated key's address. |
agentName | string | Human-readable label, e.g. @brand-desktop. |
scopes | string | Allowed actions for the delegated key. Defaults to *. |
nonce | uint256 | Server-issued; prevents replay. |
expiresAt | uint256 | Unix ms; the session/delegation expiry. |
EIP-712 — PermitDepositFor
Signed against the vault as the verifying contract.
Domain: name="Vault", version="1", chainId, verifyingContract=<vault>
| Field | Type | Description |
|---|---|---|
sender | address | Wallet funding the deposit. |
recipient | address | Credited account (your wallet). |
token | address | ERC-20 asset being deposited. |
amount | uint256 | Exact amount, in token units. |
nonce | uint256 | Replay protection. |
deadline | uint256 | Unix seconds; defaults to ~1 hour. |
The matching on-chain entry point is permitDeposit(PermitDeposit, broker). If the vault's ERC-20 allowance is insufficient, an additional ERC-2612 Permit signature is bundled alongside, so there is no separate approve() transaction.
EIP-712 — Withdraw
Signed against the payment manager as the verifying contract.
Domain: name="PaymentManagerProtocol", version="1", chainId, verifyingContract=<paymentManager>
| Field | Type | Description |
|---|---|---|
signer | address | Your main wallet. |
receiver | address | Destination wallet (defaults to signer). |
token | address | Asset being withdrawn. |
amount | uint256 | Exact amount. |
id | uint256 | Unique request ID; also acts as the nonce. |
chainId | uint256 | Bound to the target chain. |
On-chain WithdrawRequest
The vault validates a struct that carries all three required signatures together:
struct WithdrawRequest {
uint64 id;
address asset;
uint256 amount;
address receiver;
WithdrawalSignatureInfo signatureInfo;
}
struct WithdrawalSignatureInfo {
bytes userSignature; // 1. Your main wallet
bytes coreSignature; // 2. Trade system
bytes proofSignature; // 3. Proofer validator
}
If any signature is missing or invalid, the call reverts with NotEnoughSignatures or InvalidSignature. Replays revert with Replay.
Vault entry points (write)
| Function | Use |
|---|---|
permitDeposit(permit, broker) | ERC-20 deposit with embedded EIP-712 permit — no separate approve. |
deposit(dep, broker) | ERC-20 deposit when an allowance already exists. |
depositNative(dep, broker) | Native-asset (e.g. ETH) deposit. |
withdraw(req) | ERC-20 withdrawal — validates the 3-of-3 signatures. |
withdrawNative(req) | Native withdrawal — validates the 3-of-3 signatures. |
pause() / unpause() | Emergency pause / resume (PAUSE_ROLE only). |
The broker field is a numeric identifier the relayer uses to attribute deposits to a brand or integrator.
Safety mechanisms
- 3-of-3 signatures on withdraw. No subset of signers can release funds.
- Per-token hourly withdraw cap. Each whitelisted token has a
maxWithdrawPerHourceiling enforced on-chain; exceeding it reverts withMaxWithdrawCalled. - Emergency pause. A
PAUSE_ROLEaccount can freeze both deposits and withdrawals. - Role-based admin. Token whitelisting, payment-manager rotation, and contract upgrades are restricted to
ADMIN_ROLE. - Explicit failure modes. Common reverts:
InvalidSignature,ExpiredSignature,Replay,InsufficientBalance,MaxWithdrawCalled,NotEnoughSignatures,DepositFailed,WithdrawFailed.
Playground
Inspect typed-data shapes, preview signed payloads, and test the full deposit / withdraw flow at the Web3 Core Playground.