orderly-deposit-withdraw
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseOrderly Network: Deposit & Withdraw
Orderly Network:代币存提
This skill covers depositing and withdrawing assets on Orderly Network, including token approvals, vault interactions, cross-chain operations, and internal transfers.
本技能介绍了如何在Orderly Network上进行资产存提操作,包括代币授权、金库交互、跨链操作以及内部转账。
When to Use
适用场景
- Building deposit/withdrawal interfaces
- Managing collateral
- Implementing cross-chain transfers
- Handling token approvals
- Internal transfers between accounts
- 构建存提界面
- 管理抵押品
- 实现跨链转账
- 处理代币授权
- 账户间内部转账
Prerequisites
前置条件
- Connected Web3 wallet (EVM or Solana)
- Tokens on supported chain
- Understanding of ERC20 approve pattern
- Ed25519 key pair for API operations
- 已连接的Web3钱包(EVM或Solana)
- 支持链上的代币
- 了解ERC20授权机制
- 用于API操作的Ed25519密钥对
Supported Chains & Tokens
支持的链与代币
| Chain | Chain ID | USDC | USDT |
|---|---|---|---|
| Arbitrum | 42161 | ✅ | ✅ |
| Optimism | 10 | ✅ | ✅ |
| Base | 8453 | ✅ | ✅ |
| Ethereum | 1 | ✅ | ✅ |
| Mantle | 5000 | ✅ | - |
| Solana | 900900900 | ✅ | - |
Note: Fetch supported chains dynamically using
GET /v1/public/chain_info?broker_id={your_broker_id}| 链名称 | 链ID | USDC | USDT |
|---|---|---|---|
| Arbitrum | 42161 | ✅ | ✅ |
| Optimism | 10 | ✅ | ✅ |
| Base | 8453 | ✅ | ✅ |
| Ethereum | 1 | ✅ | ✅ |
| Mantle | 5000 | ✅ | - |
| Solana | 900900900 | ✅ | - |
注意:可通过动态获取支持的链信息
GET /v1/public/chain_info?broker_id={your_broker_id}Deposit Flow
存入流程
1. Fetch chain information
2. Check if token is native (ETH, SOL)
3. Approve token allowance (if not native)
4. Calculate brokerHash and tokenHash
5. Get deposit fee from vault
6. Execute deposit transaction with fee
7. Wait for confirmation
8. Balance updates on Orderly1. 获取链信息
2. 检查代币是否为原生代币(ETH、SOL)
3. 授权代币额度(非原生代币时)
4. 计算brokerHash和tokenHash
5. 从金库获取存入手续费
6. 执行包含手续费的存入交易
7. 等待交易确认
8. Orderly账户余额更新React SDK: Complete Deposit Workflow
React SDK:完整存入流程
Step 1: Fetch Chain Information
步骤1:获取链信息
typescript
import { useChain } from "@orderly.network/hooks";
function DepositForm() {
const { chains, isLoading } = useChain("USDC");
if (isLoading) return <div>Loading chains...</div>;
return (
<select>
{chains.map(chain => (
<option key={chain.id} value={chain.id}>
{chain.name}
</option>
))}
</select>
);
}typescript
import { useChain } from "@orderly.network/hooks";
function DepositForm() {
const { chains, isLoading } = useChain("USDC");
if (isLoading) return <div>Loading chains...</div>;
return (
<select>
{chains.map(chain => (
<option key={chain.id} value={chain.id}>
{chain.name}
</option>
))}
</select>
);
}Step 2: Get Deposit Metadata
步骤2:获取存入元数据
typescript
import { useDeposit } from '@orderly.network/hooks';
function DepositInfo({ tokenSymbol }: { tokenSymbol: string }) {
const { symbol, address, decimals, chainId, network } = useDeposit(tokenSymbol);
if (!address) return <div>Loading deposit info...</div>;
return (
<div>
<h3>Deposit {symbol}</h3>
<p><strong>Network:</strong> {network}</p>
<p><strong>Chain ID:</strong> {chainId}</p>
<p><strong>Contract Address:</strong> {address}</p>
<p><strong>Decimals:</strong> {decimals}</p>
<div className="mt-2 text-xs text-gray-500">
Send only {symbol} to this address on {network}.
</div>
</div>
);
}typescript
import { useDeposit } from '@orderly.network/hooks';
function DepositInfo({ tokenSymbol }: { tokenSymbol: string }) {
const { symbol, address, decimals, chainId, network } = useDeposit(tokenSymbol);
if (!address) return <div>Loading deposit info...</div>;
return (
<div>
<h3>Deposit {symbol}</h3>
<p><strong>Network:</strong> {network}</p>
<p><strong>Chain ID:</strong> {chainId}</p>
<p><strong>Contract Address:</strong> {address}</p>
<p><strong>Decimals:</strong> {decimals}</p>
<div className="mt-2 text-xs text-gray-500">
Send only {symbol} to this address on {network}.
</div>
</div>
);
}Step 3: Execute Deposit via Contract
步骤3:通过合约执行存入
typescript
import { ethers } from 'ethers';
const ERC20_ABI = [
'function approve(address spender, uint256 amount) returns (bool)',
'function allowance(address owner, address spender) view returns (uint256)',
'function balanceOf(address owner) view returns (uint256)',
];
const VAULT_ABI = [
'function deposit(tuple(bytes32 accountId, bytes32 brokerHash, bytes32 tokenHash, uint256 tokenAmount) input) external payable',
'function getDepositFee(address account, tuple(bytes32 accountId, bytes32 brokerHash, bytes32 tokenHash, uint256 tokenAmount) input) view returns (uint256)',
];
async function depositUSDC(
provider: ethers.BrowserProvider,
amount: string,
vaultAddress: string,
usdcAddress: string,
brokerId: string,
orderlyAccountId: string
) {
const signer = await provider.getSigner();
const userAddress = await signer.getAddress();
// 1. Approve token
const usdc = new ethers.Contract(usdcAddress, ERC20_ABI, signer);
const amountWei = ethers.parseUnits(amount, 6);
const allowance = await usdc.allowance(userAddress, vaultAddress);
if (allowance < amountWei) {
console.log('Approving USDC...');
const approveTx = await usdc.approve(vaultAddress, ethers.MaxUint256);
await approveTx.wait();
console.log('Approved');
}
// 2. Calculate hashes
const encoder = new TextEncoder();
const brokerHash = ethers.keccak256(encoder.encode(brokerId));
const tokenHash = ethers.keccak256(encoder.encode('USDC'));
// 3. Create deposit input struct
const depositInput = {
accountId: orderlyAccountId,
brokerHash: brokerHash,
tokenHash: tokenHash,
tokenAmount: amountWei,
};
// 4. Get deposit fee
const vault = new ethers.Contract(vaultAddress, VAULT_ABI, signer);
const depositFee = await vault.getDepositFee(userAddress, depositInput);
console.log('Deposit fee:', ethers.formatEther(depositFee), 'ETH');
// 5. Execute deposit with fee
console.log('Depositing...');
const depositTx = await vault.deposit(depositInput, { value: depositFee });
const receipt = await depositTx.wait();
console.log('Deposited:', receipt.hash);
return receipt;
}typescript
import { ethers } from 'ethers';
const ERC20_ABI = [
'function approve(address spender, uint256 amount) returns (bool)',
'function allowance(address owner, address spender) view returns (uint256)',
'function balanceOf(address owner) view returns (uint256)',
];
const VAULT_ABI = [
'function deposit(tuple(bytes32 accountId, bytes32 brokerHash, bytes32 tokenHash, uint256 tokenAmount) input) external payable',
'function getDepositFee(address account, tuple(bytes32 accountId, bytes32 brokerHash, bytes32 tokenHash, uint256 tokenAmount) input) view returns (uint256)',
];
async function depositUSDC(
provider: ethers.BrowserProvider,
amount: string,
vaultAddress: string,
usdcAddress: string,
brokerId: string,
orderlyAccountId: string
) {
const signer = await provider.getSigner();
const userAddress = await signer.getAddress();
// 1. Approve token
const usdc = new ethers.Contract(usdcAddress, ERC20_ABI, signer);
const amountWei = ethers.parseUnits(amount, 6);
const allowance = await usdc.allowance(userAddress, vaultAddress);
if (allowance < amountWei) {
console.log('Approving USDC...');
const approveTx = await usdc.approve(vaultAddress, ethers.MaxUint256);
await approveTx.wait();
console.log('Approved');
}
// 2. Calculate hashes
const encoder = new TextEncoder();
const brokerHash = ethers.keccak256(encoder.encode(brokerId));
const tokenHash = ethers.keccak256(encoder.encode('USDC'));
// 3. Create deposit input struct
const depositInput = {
accountId: orderlyAccountId,
brokerHash: brokerHash,
tokenHash: tokenHash,
tokenAmount: amountWei,
};
// 4. Get deposit fee
const vault = new ethers.Contract(vaultAddress, VAULT_ABI, signer);
const depositFee = await vault.getDepositFee(userAddress, depositInput);
console.log('Deposit fee:', ethers.formatEther(depositFee), 'ETH');
// 5. Execute deposit with fee
console.log('Depositing...');
const depositTx = await vault.deposit(depositInput, { value: depositFee });
const receipt = await depositTx.wait();
console.log('Deposited:', receipt.hash);
return receipt;
}REST API: Get Deposit Info
REST API:获取存入信息
typescript
// Get supported tokens with collateral factors
GET /v1/public/token
// Response
{
"success": true,
"data": {
"rows": [
{
"token": "USDC",
"decimals": 6,
"address": {
"42161": "0xaf88d065e77c8cC2239327C5EDb3A432268e5831",
"10": "0x0b2C639c533813f4Aa9D7837CAf62653d097Ff85"
},
"collateral_factor": 1.0
},
{
"token": "USDT",
"decimals": 6,
"address": { ... },
"collateral_factor": 0.95
}
]
}
}
// Get chain info
GET /v1/public/chain_info?broker_id={broker_id}
// Get vault balance (TVL)
GET /v1/public/vault_balancetypescript
// Get supported tokens with collateral factors
GET /v1/public/token
// Response
{
"success": true,
"data": {
"rows": [
{
"token": "USDC",
"decimals": 6,
"address": {
"42161": "0xaf88d065e77c8cC2239327C5EDb3A432268e5831",
"10": "0x0b2C639c533813f4Aa9D7837CAf62653d097Ff85"
},
"collateral_factor": 1.0
},
{
"token": "USDT",
"decimals": 6,
"address": { ... },
"collateral_factor": 0.95
}
]
}
}
// Get chain info
GET /v1/public/chain_info?broker_id={broker_id}
// Get vault balance (TVL)
GET /v1/public/vault_balanceUnderstanding Collateral Factors
理解抵押系数
Each token has a collateral factor (0.0 to 1.0) that determines how much of your deposit counts toward trading collateral:
| Token | Collateral Factor | $1000 Deposit = Collateral Value |
|---|---|---|
| USDC | 1.0 (100%) | $1000 |
| USDT | 0.95 (95%) | $950 |
| Other | Varies | Depends on risk assessment |
Example: If you deposit $1000 USDT with a 0.95 collateral factor, only $950 counts as collateral for margin calculations.
每个代币都有一个抵押系数(0.0到1.0),用于计算存入资产可作为交易抵押品的比例:
| 代币 | 抵押系数 | 1000美元存入对应的抵押品价值 |
|---|---|---|
| USDC | 1.0 (100%) | 1000美元 |
| USDT | 0.95 (95%) | 950美元 |
| 其他代币 | 依情况而定 | 取决于风险评估 |
示例:若你存入1000美元USDT,其抵押系数为0.95,则只有950美元会被计入保证金计算的抵押品价值。
Withdrawal Flow
提取流程
1. Get withdrawal nonce
2. Sign withdrawal message with EIP-712 (EVM) or Ed25519 (Solana)
3. Submit signed request with Ed25519 API auth
4. Wait for processing
5. Receive tokens on chain1. 获取提取随机数
2. 使用EIP-712(EVM)或Ed25519(Solana)签署提取消息
3. 通过Ed25519 API认证提交已签名的请求
4. 等待处理
5. 链上接收代币React SDK: useWithdraw Hook
React SDK:useWithdraw Hook
typescript
import { useWithdraw } from '@orderly.network/hooks';
function WithdrawForm() {
const { withdraw, isLoading } = useWithdraw();
const [amount, setAmount] = useState('');
const [destination, setDestination] = useState('');
const handleWithdraw = async () => {
try {
await withdraw({
symbol: "USDC",
amount: "50",
address: "0x123...",
chainId: 1, // Ethereum Mainnet
network: "ethereum"
});
alert('Withdrawal initiated!');
} catch (error) {
console.error('Withdrawal failed:', error);
}
};
return (
<div className="withdraw-form">
<input
type="text"
placeholder="Amount"
value={amount}
onChange={(e) => setAmount(e.target.value)}
/>
<input
type="text"
placeholder="Destination Address"
value={destination}
onChange={(e) => setDestination(e.target.value)}
/>
<button onClick={handleWithdraw} disabled={isLoading}>
{isLoading ? 'Processing...' : 'Withdraw'}
</button>
</div>
);
}typescript
import { useWithdraw } from '@orderly.network/hooks';
function WithdrawForm() {
const { withdraw, isLoading } = useWithdraw();
const [amount, setAmount] = useState('');
const [destination, setDestination] = useState('');
const handleWithdraw = async () => {
try {
await withdraw({
symbol: "USDC",
amount: "50",
address: "0x123...",
chainId: 1, // Ethereum Mainnet
network: "ethereum"
});
alert('Withdrawal initiated!');
} catch (error) {
console.error('Withdrawal failed:', error);
}
};
return (
<div className="withdraw-form">
<input
type="text"
placeholder="Amount"
value={amount}
onChange={(e) => setAmount(e.target.value)}
/>
<input
type="text"
placeholder="Destination Address"
value={destination}
onChange={(e) => setDestination(e.target.value)}
/>
<button onClick={handleWithdraw} disabled={isLoading}>
{isLoading ? 'Processing...' : 'Withdraw'}
</button>
</div>
);
}REST API: Withdrawal
REST API:提取操作
Step 1: Get Withdrawal Nonce
步骤1:获取提取随机数
typescript
GET /v1/withdraw_nonce
// Requires Ed25519 API authentication
// Response
{
"success": true,
"data": {
"withdraw_nonce": 123456
}
}typescript
GET /v1/withdraw_nonce
// Requires Ed25519 API authentication
// Response
{
"success": true,
"data": {
"withdraw_nonce": 123456
}
}Step 2: Create EIP-712 Signature (EVM)
步骤2:创建EIP-712签名(EVM)
typescript
// Use ON-CHAIN domain for withdrawals (see EIP-712 Domain Configuration in orderly-api-authentication)
const domain = {
name: 'Orderly',
version: '1',
chainId: 42161,
verifyingContract: '0x6F7a338F2aA472838dEFD3283eB360d4Dff5D203', // Mainnet Ledger
// verifyingContract: '0x1826B75e2ef249173FC735149AE4B8e9ea10abff' // Testnet Ledger
};
const types = {
Withdraw: [
{ name: 'brokerId', type: 'string' },
{ name: 'chainId', type: 'uint256' },
{ name: 'receiver', type: 'address' },
{ name: 'token', type: 'string' },
{ name: 'amount', type: 'uint256' },
{ name: 'withdrawNonce', type: 'uint64' },
{ name: 'timestamp', type: 'uint64' },
],
};
const withdrawMessage = {
brokerId: 'woofi_dex',
chainId: 42161,
receiver: '0xTargetAddress',
token: 'USDC',
amount: '10000000', // 10 USDC (6 decimals)
withdrawNonce: withdrawNonceFromStep1,
timestamp: Date.now(),
};
// Sign with wallet
const signature = await wallet.signTypedData(domain, types, withdrawMessage);typescript
// Use ON-CHAIN domain for withdrawals (see EIP-712 Domain Configuration in orderly-api-authentication)
const domain = {
name: 'Orderly',
version: '1',
chainId: 42161,
verifyingContract: '0x6F7a338F2aA472838dEFD3283eB360d4Dff5D203', // Mainnet Ledger
// verifyingContract: '0x1826B75e2ef249173FC735149AE4B8e9ea10abff' // Testnet Ledger
};
const types = {
Withdraw: [
{ name: 'brokerId', type: 'string' },
{ name: 'chainId', type: 'uint256' },
{ name: 'receiver', type: 'address' },
{ name: 'token', type: 'string' },
{ name: 'amount', type: 'uint256' },
{ name: 'withdrawNonce', type: 'uint64' },
{ name: 'timestamp', type: 'uint64' },
],
};
const withdrawMessage = {
brokerId: 'woofi_dex',
chainId: 42161,
receiver: '0xTargetAddress',
token: 'USDC',
amount: '10000000', // 10 USDC (6 decimals)
withdrawNonce: withdrawNonceFromStep1,
timestamp: Date.now(),
};
// Sign with wallet
const signature = await wallet.signTypedData(domain, types, withdrawMessage);Step 3: Submit Withdrawal Request
步骤3:提交提取请求
typescript
POST /v1/withdraw_request
Body: {
"message": withdrawMessage,
"signature": "0x..."
}
// Requires Ed25519 API authentication
// Response
{
"success": true,
"data": {
"withdraw_id": 123
},
"timestamp": 1702989203989
}typescript
POST /v1/withdraw_request
Body: {
"message": withdrawMessage,
"signature": "0x..."
}
// Requires Ed25519 API authentication
// Response
{
"success": true,
"data": {
"withdraw_id": 123
},
"timestamp": 1702989203989
}Withdrawal for Solana
Solana提取操作
typescript
import { DefaultSolanaWalletAdapter } from '@orderly.network/default-solana-adapter';
import { signAsync } from '@noble/ed25519';
const walletAdapter = new DefaultSolanaWalletAdapter();
await walletAdapter.active({
address: solanaAddress,
provider: {
signMessage: async (msg: Uint8Array) => {
return await signAsync(msg, privateKey);
}
}
});
const withdrawMessage = await walletAdapter.generateWithdrawMessage({
brokerId: BROKER_ID,
receiver: solanaAddress,
token: 'USDC',
amount: '1000',
timestamp: Date.now(),
nonce: withdrawNonceFromStep1,
});
const signature = await walletAdapter.signMessage(withdrawMessage.message);
// Submit withdrawal request
POST /v1/withdraw_request
Body: {
"message": withdrawMessage.message,
"signature": signature,
"userAddress": solanaAddress,
"verifyingContract": "0x6F7a338F2aA472838dEFD3283eB360d4Dff5D203"
// "verifyingContract": "0x1826B75e2ef249173FC735149AE4B8e9ea10abff"
}
Headers: { Standard Orderly Auth Headers }typescript
import { DefaultSolanaWalletAdapter } from '@orderly.network/default-solana-adapter';
import { signAsync } from '@noble/ed25519';
const walletAdapter = new DefaultSolanaWalletAdapter();
await walletAdapter.active({
address: solanaAddress,
provider: {
signMessage: async (msg: Uint8Array) => {
return await signAsync(msg, privateKey);
}
}
});
const withdrawMessage = await walletAdapter.generateWithdrawMessage({
brokerId: BROKER_ID,
receiver: solanaAddress,
token: 'USDC',
amount: '1000',
timestamp: Date.now(),
nonce: withdrawNonceFromStep1,
});
const signature = await walletAdapter.signMessage(withdrawMessage.message);
// Submit withdrawal request
POST /v1/withdraw_request
Body: {
"message": withdrawMessage.message,
"signature": signature,
"userAddress": solanaAddress,
"verifyingContract": "0x6F7a338F2aA472838dEFD3283eB360d4Dff5D203"
// "verifyingContract": "0x1826B75e2ef249173FC735149AE4B8e9ea10abff"
}
Headers: { Standard Orderly Auth Headers }Cross-Chain Withdrawal
跨链提取
Cross-chain withdrawal is required when the destination chain differs from the chain where funds were deposited.
typescript
POST /v1/withdraw_request
Body: {
"message": {
...withdrawMessage,
"chainId": 10,
"allowCrossChainWithdraw": true
},
"signature": signature,
"userAddress": walletAddress,
"verifyingContract": "0x6F7a338F2aA472838dEFD3283eB360d4Dff5D203"
}
// Requires Ed25519 API authentication
// Response
{
"success": true,
"data": {
"withdraw_id": 123
},
"timestamp": 1702989203989
}Error Code 22: If is when a cross-chain withdrawal is needed, the API returns:
allowCrossChainWithdrawfalsejson
{
"success": false,
"code": 22,
"message": "Cross-chain withdrawal required for this withdrawal request"
}当目标链与存入资产的链不同时,需要使用跨链提取。
typescript
POST /v1/withdraw_request
Body: {
"message": {
...withdrawMessage,
"chainId": 10,
"allowCrossChainWithdraw": true
},
"signature": signature,
"userAddress": walletAddress,
"verifyingContract": "0x6F7a338F2aA472838dEFD3283eB360d4Dff5D203"
}
// Requires Ed25519 API authentication
// Response
{
"success": true,
"data": {
"withdraw_id": 123
},
"timestamp": 1702989203989
}错误码22:若跨链提取需要但设为,API会返回:
allowCrossChainWithdrawfalsejson
{
"success": false,
"code": 22,
"message": "Cross-chain withdrawal required for this withdrawal request"
}Internal Transfer
内部转账
Transfer funds between Orderly accounts instantly with no gas fees.
在Orderly账户间即时转账,无需Gas费。
React SDK: useInternalTransfer Hook
React SDK:useInternalTransfer Hook
typescript
import { useInternalTransfer } from '@orderly.network/hooks';
function TransferFunds() {
const [amount, setAmount] = useState('');
const { transfer, isLoading } = useInternalTransfer();
const handleTransfer = async () => {
try {
await transfer({
token: 'USDC',
amount: parseFloat(amount),
});
alert('Transfer successful!');
} catch (e) {
console.error(e);
}
};
return (
<div>
<input
type="number"
value={amount}
onChange={(e) => setAmount(e.target.value)}
placeholder="Amount"
/>
<button
onClick={handleTransfer}
disabled={isLoading || !amount}
>
{isLoading ? 'Transferring...' : 'Transfer'}
</button>
</div>
);
}typescript
import { useInternalTransfer } from '@orderly.network/hooks';
function TransferFunds() {
const [amount, setAmount] = useState('');
const { transfer, isLoading } = useInternalTransfer();
const handleTransfer = async () => {
try {
await transfer({
token: 'USDC',
amount: parseFloat(amount),
});
alert('Transfer successful!');
} catch (e) {
console.error(e);
}
};
return (
<div>
<input
type="number"
value={amount}
onChange={(e) => setAmount(e.target.value)}
placeholder="Amount"
/>
<button
onClick={handleTransfer}
disabled={isLoading || !amount}
>
{isLoading ? 'Transferring...' : 'Transfer'}
</button>
</div>
);
}REST API: Internal Transfer (v2)
REST API:内部转账(v2)
Internal transfers move funds between Orderly accounts instantly with no gas fees.
Allowed scenarios:
- Main and sub-accounts
- Accounts within the same wallet group
- Same address across all brokers
- Whitelisted accounts
- Accounts under the same whitelisted broker
内部转账可在Orderly账户间即时转移资金,无需Gas费。
允许的场景:
- 主账户与子账户
- 同一钱包组内的账户
- 所有经纪商下的相同地址
- 白名单账户
- 同一白名单经纪商下的账户
EVM (EIP-712 Signing)
EVM(EIP-712签名)
typescript
// Step 1: Get transfer nonce (Ed25519 API auth)
GET /v1/transfer_nonce
// Requires Ed25519 API authentication
// Response
{
"success": true,
"data": {
"transfer_nonce": "789012"
}
}
// Step 2: Sign EIP-712 message with wallet (ON-CHAIN domain - see orderly-api-authentication)
const receiverHex = receiverAddress.startsWith('0x')
? receiverAddress.slice(2)
: receiverAddress;
const receiverBytes32 = ethers.zeroPadValue('0x' + receiverHex, 32);
const domain = {
name: 'Orderly',
version: '1',
chainId: 42161,
verifyingContract: '0x6F7a338F2aA472838dEFD3283eB360d4Dff5D203' // Mainnet Ledger
};
const types = {
InternalTransfer: [
{ name: 'receiver', type: 'bytes32' },
{ name: 'token', type: 'string' },
{ name: 'amount', type: 'uint256' },
{ name: 'transferNonce', type: 'uint64' }
]
};
const message = {
receiver: receiverBytes32,
token: 'USDC',
amount: ethers.parseUnits('100', 6),
transferNonce: Number(transferNonce)
};
const signature = await wallet.signTypedData(domain, types, message);
// Step 3: Submit to v2 endpoint
POST /v2/internal_transfer
Body: {
"message": {
"receiver": "0xReceiverAddress",
"token": "USDC",
"amount": "100",
"transferNonce": "789012",
"chainId": "42161",
"chainType": "EVM"
},
"signature": "0x...",
"userAddress": "0xSenderAddress",
"verifyingContract": "0x6F7a338F2aA472838dEFD3283eB360d4Dff5D203"
}
// Requires Ed25519 API authenticationtypescript
// Step 1: Get transfer nonce (Ed25519 API auth)
GET /v1/transfer_nonce
// Requires Ed25519 API authentication
// Response
{
"success": true,
"data": {
"transfer_nonce": "789012"
}
}
// Step 2: Sign EIP-712 message with wallet (ON-CHAIN domain - see orderly-api-authentication)
const receiverHex = receiverAddress.startsWith('0x')
? receiverAddress.slice(2)
: receiverAddress;
const receiverBytes32 = ethers.zeroPadValue('0x' + receiverHex, 32);
const domain = {
name: 'Orderly',
version: '1',
chainId: 42161,
verifyingContract: '0x6F7a338F2aA472838dEFD3283eB360d4Dff5D203' // Mainnet Ledger
};
const types = {
InternalTransfer: [
{ name: 'receiver', type: 'bytes32' },
{ name: 'token', type: 'string' },
{ name: 'amount', type: 'uint256' },
{ name: 'transferNonce', type: 'uint64' }
]
};
const message = {
receiver: receiverBytes32,
token: 'USDC',
amount: ethers.parseUnits('100', 6),
transferNonce: Number(transferNonce)
};
const signature = await wallet.signTypedData(domain, types, message);
// Step 3: Submit to v2 endpoint
POST /v2/internal_transfer
Body: {
"message": {
"receiver": "0xReceiverAddress",
"token": "USDC",
"amount": "100",
"transferNonce": "789012",
"chainId": "42161",
"chainType": "EVM"
},
"signature": "0x...",
"userAddress": "0xSenderAddress",
"verifyingContract": "0x6F7a338F2aA472838dEFD3283eB360d4Dff5D203"
}
// Requires Ed25519 API authenticationSolana (Adapter Signing)
Solana(适配器签名)
typescript
import { DefaultSolanaWalletAdapter } from '@orderly.network/default-solana-adapter';
// Step 1: Get transfer nonce
GET /v1/transfer_nonce
// Requires Ed25519 API authentication
// Step 2: Generate and sign message with adapter
const walletAdapter = new DefaultSolanaWalletAdapter();
// ... initialize adapter ...
const transferMessage = await walletAdapter.generateTransferMessage({
receiver: receiverAddress,
token: 'USDC',
amount: '100',
transferNonce: nonceFromStep1,
chainId: 900900900,
chainType: 'SOL'
});
const signature = await walletAdapter.signMessage(transferMessage.message);
// Step 3: Submit to v2 endpoint
POST /v2/internal_transfer
Body: {
"message": {
"receiver": "SolanaReceiverAddress",
"token": "USDC",
"amount": "100",
"transferNonce": "789012",
"chainId": "900900900",
"chainType": "SOL"
},
"signature": signature,
"userAddress": solanaAddress,
"verifyingContract": "0x6F7a338F2aA472838dEFD3283eB360d4Dff5D203"
}
// Requires Ed25519 API authenticationImportant Notes:
- Transfer nonce must be obtained before each transfer (via Ed25519 auth)
- The actual transfer requires wallet signature (EIP-712 for EVM, adapter for Solana)
- Receiver address must be converted to bytes32 for EVM signing
- Internal transfers are not available for Delegate Signer accounts
- v2 endpoint includes optional memo field
typescript
import { DefaultSolanaWalletAdapter } from '@orderly.network/default-solana-adapter';
// Step 1: Get transfer nonce
GET /v1/transfer_nonce
// Requires Ed25519 API authentication
// Step 2: Generate and sign message with adapter
const walletAdapter = new DefaultSolanaWalletAdapter();
// ... initialize adapter ...
const transferMessage = await walletAdapter.generateTransferMessage({
receiver: receiverAddress,
token: 'USDC',
amount: '100',
transferNonce: nonceFromStep1,
chainId: 900900900,
chainType: 'SOL'
});
const signature = await walletAdapter.signMessage(transferMessage.message);
// Step 3: Submit to v2 endpoint
POST /v2/internal_transfer
Body: {
"message": {
"receiver": "SolanaReceiverAddress",
"token": "USDC",
"amount": "100",
"transferNonce": "789012",
"chainId": "900900900",
"chainType": "SOL"
},
"signature": signature,
"userAddress": solanaAddress,
"verifyingContract": "0x6F7a338F2aA472838dEFD3283eB360d4Dff5D203"
}
// Requires Ed25519 API authentication重要说明:
- 每次转账前必须获取转账随机数(通过Ed25519认证)
- 实际转账需要钱包签名(EVM使用EIP-712,Solana使用适配器)
- EVM签名时需将接收方地址转换为bytes32格式
- 代理签名账户不支持内部转账
- v2端点支持可选的备注字段
Asset History
资产历史
typescript
// Get deposit/withdrawal history
GET /v1/asset/history?token=USDC&side=DEPOSIT&page=1&size=20
// Requires Ed25519 API authentication
// Query parameters (all optional):
// token: USDC
// side: DEPOSIT | WITHDRAW
// status: NEW | CONFIRM | PROCESSING | COMPLETED | FAILED | PENDING_REBALANCE
// start_t: timestamp (e.g., 1702989203989)
// end_t: timestamp (e.g., 1702989203989)
// page: 1 (default)
// size: 20 (default)
// Response
{
"success": true,
"data": {
"rows": [
{
"id": "tx_123",
"token": "USDC",
"side": "DEPOSIT",
"amount": "1000.00",
"status": "COMPLETED",
"tx_hash": "0x...",
"chain_id": 42161,
"created_at": 1699123456
}
],
"total": 50
}
}typescript
// Get deposit/withdrawal history
GET /v1/asset/history?token=USDC&side=DEPOSIT&page=1&size=20
// Requires Ed25519 API authentication
// Query parameters (all optional):
// token: USDC
// side: DEPOSIT | WITHDRAW
// status: NEW | CONFIRM | PROCESSING | COMPLETED | FAILED | PENDING_REBALANCE
// start_t: timestamp (e.g., 1702989203989)
// end_t: timestamp (e.g., 1702989203989)
// page: 1 (default)
// size: 20 (default)
// Response
{
"success": true,
"data": {
"rows": [
{
"id": "tx_123",
"token": "USDC",
"side": "DEPOSIT",
"amount": "1000.00",
"status": "COMPLETED",
"tx_hash": "0x...",
"chain_id": 42161,
"created_at": 1699123456
}
],
"total": 50
}
}Testnet Faucet
测试网水龙头
typescript
// Get testnet USDC (testnet only)
POST /v1/faucet/usdc
Headers: { Standard Orderly Auth Headers }
// EVM Testnet
POST https://testnet-operator-evm.orderly.org/v1/faucet/usdc
// Solana Testnet
POST https://testnet-operator-sol.orderly.org/v1/faucet/usdc
// Each account can use faucet max 5 times
// EVM: 1000 USDC per request
// Solana: 100 USDC per requesttypescript
// Get testnet USDC (testnet only)
POST /v1/faucet/usdc
Headers: { Standard Orderly Auth Headers }
// EVM Testnet
POST https://testnet-operator-evm.orderly.org/v1/faucet/usdc
// Solana Testnet
POST https://testnet-operator-sol.orderly.org/v1/faucet/usdc
// Each account can use faucet max 5 times
// EVM: 1000 USDC per request
// Solana: 100 USDC per requestGet Contract Addresses
获取合约地址
typescript
import { getContractAddresses } from '@orderly.network/contracts';
// EVM chains
const addresses = getContractAddresses('arbitrum', 'mainnet');
// {
// vault: '0x816f722424B49Cf1275cc86DA9840Fbd5a6167e9',
// usdc: '0xaf88d065e77c8cC2239327C5EDb3A432268e5831',
// usdt: '0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9'
// }
// Or fetch dynamically
GET /v1/public/chain_info?broker_id={broker_id}typescript
import { getContractAddresses } from '@orderly.network/contracts';
// EVM chains
const addresses = getContractAddresses('arbitrum', 'mainnet');
// {
// vault: '0x816f722424B49Cf1275cc86DA9840Fbd5a6167e9',
// usdc: '0xaf88d065e77c8cC2239327C5EDb3A432268e5831',
// usdt: '0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9'
// }
// Or fetch dynamically
GET /v1/public/chain_info?broker_id={broker_id}Verifying Contract Addresses
验证合约地址
| Environment | Verifying Contract |
|---|---|
| Mainnet | |
| Testnet | |
| 环境 | 验证合约地址 |
|---|---|
| 主网 | |
| 测试网 | |
Common Issues
常见问题
"Insufficient allowance" error
"Insufficient allowance" 错误
- Call before deposit
approve() - Check if approval transaction confirmed
- Ensure you're approving the vault address, not token address
- 存入前调用
approve() - 检查授权交易是否已确认
- 确保授权的是金库地址而非代币地址
"Insufficient balance" error
"Insufficient balance" 错误
- Check wallet balance, not just Orderly balance
- Ensure correct token decimals
- Account for deposit fee (native token like ETH)
- 检查钱包余额,而非仅Orderly账户余额
- 确保代币小数位数正确
- 考虑存入手续费(如ETH等原生代币)
Withdrawal stuck in "PROCESSING"
提取操作卡在"PROCESSING"状态
- Check for status updates
/v1/asset/history - Contact support if stuck > 24 hours
- 调用获取状态更新
/v1/asset/history - 若超过24小时仍未处理,请联系支持团队
"Cross-chain withdrawal required" error (Code 22)
"Cross-chain withdrawal required" 错误(代码22)
- Set in request body
allow_cross_chain_withdrawal: true - Destination chain differs from deposit chain
- Expect longer processing time
- 在请求体中设置
allow_cross_chain_withdrawal: true - 目标链与存入链不同
- 处理时间会更长
Internal transfer not available
内部转账不可用
- Not available for Delegate Signer accounts
- Ensure accounts meet allowed transfer scenarios
- Check that Ed25519 authentication is properly signed
- 代理签名账户不支持内部转账
- 确保账户符合允许的转账场景
- 检查Ed25519认证是否正确签署
EIP-712 signature mismatch
EIP-712签名不匹配
Common mistakes:
- type should be
withdrawNonce, notuint64uint256 - type should be
token, notstringaddress - Missing field in message
fee - Wrong verifying contract address
- Wrong chain ID in domain
常见错误:
- 类型应为
withdrawNonce而非uint64uint256 - 类型应为
token而非stringaddress - 消息中缺少字段
fee - 验证合约地址错误
- 域中的链ID错误
Related Skills
相关技能
- orderly-api-authentication - Ed25519 API authentication and EIP-712 signing
- orderly-sdk-react-hooks - React SDK hooks reference
- orderly-onboarding - Account setup and getting started
- orderly-api-authentication - Ed25519 API认证与EIP-712签名
- orderly-sdk-react-hooks - React SDK Hook参考
- orderly-onboarding - 账户设置与入门指南