mcpField
O
orderly-deposit-withdraw

orderly-deposit-withdraw

github.com/orderlynetworkその他264 回インストール1 日前に更新
リポジトリ

orderly-deposit-withdraw について

Orderly Networkで入金、出金、内部振替を実装する開発者向けスキルです。ウォレット署名、トークン承認、クロスチェーン処理を、React HooksとREST APIの例とともに扱います。

主な機能

  1. 01トークン承認を伴う入金フロー
  2. 02ウォレット署名による出金
  3. 03クロスチェーン出金への対応
  4. 04Orderlyアカウント間の振替
  5. 05資産履歴とテストネットフォーセット

活用シーン

  1. 01入金画面の構築
  2. 02クロスチェーン出金の実装
  3. 03担保入金の管理
  4. 04Orderlyアカウント間の資金移動

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/orderlynetwork/skills --skill orderly-deposit-withdraw

インストール後、Claude Code で/orderly-deposit-withdrawを入力して読み込まれたか確認します。

詳細

Orderly Network:入金と出金

このスキルでは、トークンの承認、Vault とのやり取り、クロスチェーン操作、内部振替など、Orderly Network での資産の入金と出金について説明します。

使用する場面

  • 入金・出金インターフェースの構築
  • 担保の管理
  • クロスチェーン振替の実装
  • トークンの承認処理
  • アカウント間の内部振替

前提条件

  • 接続済みの Web3 ウォレット(EVM または Solana)
  • 対応チェーン上のトークン
  • ERC20 の approve パターンに関する理解
  • API 操作用の Ed25519 キーペア

対応チェーンとトークン

チェーンチェーン IDUSDCUSDT
Arbitrum42161✅✅
Optimism10✅✅
Base8453✅✅
Ethereum1✅✅
Mantle5000✅-
Solana900900900✅-

注:GET /v1/public/chain_info?broker_id={your_broker_id} を使って、対応チェーンを動的に取得してください。

入金フロー

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 Orderly

React SDK:入金ワークフロー全体

ステップ 1:チェーン情報を取得
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>
  );
}
ステップ 2:入金メタデータを取得
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>
  );
}
ステップ 3:コントラクト経由で入金を実行
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 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_balance
担保係数について

各トークンには担保係数(0.0~1.0)があり、入金額のうち取引担保として計上される金額を決定します。

トークン担保係数入金額 $1000 = 担保価値
USDC1.0(100%)$1000
USDT0.95(95%)$950
その他変動リスク評価による

例:担保係数が 0.95 の場合、USDT を $1000 入金すると、証拠金の計算において担保として計上されるのは $950 のみです。

出金フロー

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 chain

React SDK:useWithdraw フック

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:出金

ステップ 1:出金 nonce を取得
GET /v1/withdraw_nonce
// Requires Ed25519 API authentication

// Response
{
  "success": true,
  "data": {
    "withdraw_nonce": 123456
  }
}
ステップ 2:EIP-712 署名を作成(EVM)
// 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);
ステップ 3:出金リクエストを送信
POST /v1/withdraw_request
Body: {
  "message": withdrawMessage,
  "signature": "0x..."
}
// Requires Ed25519 API authentication

// Response
{
  "success": true,
  "data": {
    "withdraw_id": 123
  },
  "timestamp": 1702989203989
}
Solana での出金
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 }

クロスチェーン出金

入金したチェーンとは異なるチェーンを出金先にする場合、クロスチェーン出金が必要です。

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:クロスチェーン出金が必要なときに allowCrossChainWithdraw が false の場合、API は次を返します。

{
  "success": false,
  "code": 22,
  "message": "Cross-chain withdrawal required for this withdrawal request"
}

内部振替

ガス代なしで、Orderly アカウント間の資金を即時に振り替えます。

React SDK:useInternalTransfer フック
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:内部振替(v2)

内部振替では、ガス代なしで Orderly アカウント間の資金を即時に移動できます。

許可されるケース:

  • メインアカウントとサブアカウント間
  • 同じウォレットグループ内のアカウント間
  • すべてのブローカーで同じアドレスを使用する場合
  • ホワイトリスト登録済みアカウント
  • 同じホワイトリスト登録済みブローカー配下のアカウント
EVM(EIP-712 署名)
// 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 authentication
Solana(アダプター署名)
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

重要な注意事項:

  • 振替ごとに、振替 nonce を取得する必要があります(Ed25519 認証を使用)
  • 実際の振替にはウォレット署名が必要です(EVM では EIP-712、Solana ではアダプター)
  • EVM での署名では、受取人のアドレスを bytes32 に変換する必要があります
  • Delegate Signer アカウントでは内部振替を利用できません
  • v2 エンドポイントには任意の memo フィールドが含まれます

資産履歴

// 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
  }
}

テストネットの Faucet

// 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 request

コントラクトアドレスの取得

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}
コントラクトアドレスの検証
環境検証用コントラクト
メインネット0x6F7a338F2aA472838dEFD3283eB360d4Dff5D203
テストネット0x1826B75e2ef249173FC735149AE4B8e9ea10abff

よくある問題

「Insufficient allowance」エラー
  • 入金前に approve() を呼び出してください
  • 承認トランザクションが確定したか確認してください
  • トークンアドレスではなく、Vault アドレスを承認していることを確認してください
"Insufficient balance" エラー
  • Orderly の残高だけでなく、ウォレットの残高も確認してください
  • トークンの小数桁数が正しいことを確認してください
  • 入金手数料(ETH などのネイティブトークン)を考慮してください
"PROCESSING" のまま出金が進まない
  • /v1/asset/history でステータスの更新を確認してください
  • 24 時間以上進展しない場合は、サポートにお問い合わせください
"Cross-chain withdrawal required" エラー(コード 22)
  • リクエスト本文で allow_cross_chain_withdrawal: true を設定してください
  • 出金先チェーンが入金元チェーンと異なります
  • 処理に時間がかかることを想定してください
内部送金を利用できない
  • Delegate Signer アカウントでは利用できません
  • アカウントが許可されている送金シナリオを満たしていることを確認してください
  • Ed25519 認証が正しく署名されていることを確認してください
EIP-712 署名の不一致

よくある間違い:

  • withdrawNonce の型は uint256 ではなく uint64 にしてください
  • token の型は address ではなく string にしてください
  • メッセージに fee フィールドがない
  • 検証コントラクトアドレスが間違っている
  • ドメインのチェーン ID が間違っている

関連スキル

  • orderly-api-authentication - Ed25519 API 認証と EIP-712 署名
  • orderly-sdk-react-hooks - React SDK フックのリファレンス
  • orderly-onboarding - アカウント設定と利用開始

コメント