Skip to main content

Domain

const domain = {
  name: 'PredictStreetVault',
  version: '1',
  chainId: 99999,
  verifyingContract: '<YOUR VAULT ADDRESS>',
};
verifyingContract is your vault clone, not the factory. Fetch via GET /api/mevaultAddress, or on-chain via VaultFactory.vaultOf(eoa).

Struct

struct WithdrawERC20 {
    address token;
    address to;
    uint256 amount;
    uint256 salt;
    uint256 deadline;
}
salt is not a sequential nonce — it’s a one-time uniqueness field you choose. The vault tracks usedDigests[digest].

Signing example

const types = {
  WithdrawERC20: [
    { name: 'token', type: 'address' },
    { name: 'to', type: 'address' },
    { name: 'amount', type: 'uint256' },
    { name: 'salt', type: 'uint256' },
    { name: 'deadline', type: 'uint256' },
  ],
};

const message = {
  token: USDC_ADDRESS,
  to: destinationWallet,
  amount: BigInt('100000000'),
  salt: BigInt(`0x${randomBytes(32).toString('hex')}`),
  deadline: BigInt(Math.floor(Date.now() / 1000) + 86400),
};

const signature = await wallet.signTypedData(domain, types, message);

Request

POST /api/withdrawals/request
# Withdrawal endpoints aren't exposed on the partner API today.
Content-Type: application/json

{
  "userWallet": "0x...",
  "amount": "100",
  "destination": "0x...",
  "userSignature": "0x...",
  "salt": "0x...",
  "deadline": 1713800000
}
Response mirrors the current state after the request. Subscribe to withdrawals.me WebSocket channel for transitions.