Skip to main content

What does transfer do?

The transfer command validates an ERC20 token transfer against the policy engine. It sets action to transfer automatically, so you only provide the recipient, amount, token, and reason. This is a convenience wrapper around validate for the most common operation.
npx @mandate.md/cli transfer \
  --to 0xRecipientAddress \
  --amount 50 \
  --token USDC \
  --reason "Payment for services"

Options

FlagRequiredDescription
--toYesRecipient address (0x…)
--amountYesAmount in token units
--tokenYesToken symbol (e.g. USDC) or contract address
--reasonYesWhy this transfer is being sent
--chainNoChain name or ID (preflight mode)
--rawNoUse raw EVM validation (legacy)

Raw mode flags (only with --raw)

FlagRequiredDefaultDescription
--nonceYes-Transaction nonce
--maxFeePerGasYes-Max fee per gas (wei)
--maxPriorityFeePerGasYes-Max priority fee per gas (wei)
--gasLimitNo65000Gas limit
--chainIdNoFrom credentialsChain ID

Preflight mode (default)

In preflight mode, the command sends an action-based validation request. No gas parameters needed.
npx @mandate.md/cli transfer \
  --to 0x036CbD53842c5426634e7929541eC2318f3dCF7e \
  --amount 10 \
  --token USDC \
  --reason "Invoice #42"

Output

{
  "ok": true,
  "intentId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "feedback": "Mandate: policy check passed"
}
If the policy blocks the transfer, the output includes error and blockReason:
{
  "error": "POLICY_BLOCKED",
  "message": "Mandate: blocked: amount exceeds daily limit",
  "blockReason": "SPEND_LIMIT_PER_DAY"
}
If approval is required, the output includes the intentId and a next field pointing to mandate approve.

Raw mode (legacy)

Deprecated. Use preflight mode instead. Raw mode is kept for legacy self-custodial flows.
Raw mode encodes the ERC20 transfer(address,uint256) calldata, computes the intentHash, and sends a raw validation request. On success, it returns the unsigned transaction for manual signing.
npx @mandate.md/cli transfer --raw \
  --to 0xRecipientAddress \
  --amount 10000000 \
  --token 0x036CbD53842c5426634e7929541eC2318f3dCF7e \
  --reason "Invoice #127" \
  --nonce 42 \
  --maxFeePerGas 1000000000 \
  --maxPriorityFeePerGas 1000000000

Raw mode output

{
  "ok": true,
  "intentId": "a1b2c3d4-...",
  "feedback": "Mandate: policy check passed",
  "unsignedTx": {
    "to": "0x036CbD53842c5426634e7929541eC2318f3dCF7e",
    "calldata": "0xa9059cbb...",
    "value": "0",
    "gasLimit": "65000",
    "maxFeePerGas": "1000000000",
    "maxPriorityFeePerGas": "1000000000",
    "nonce": 42,
    "chainId": 84532
  },
  "next": "Run: mandate event a1b2c3d4-... --tx-hash 0x..."
}
Sign the unsignedTx with your private key, broadcast it, then post the txHash with mandate event.

Next Steps

Post Transaction Hash

Report the txHash after signing and broadcasting.

Check Intent Status

Poll the intent state until confirmed.

MandateWallet SDK

Automate the full flow programmatically with the TypeScript SDK.