Skip to main content
An intent is a desired action on your account in the Verifier smart contract, performed by submitting a transaction to the NEAR blockchain. The Verifier allows submitting a list of actions using the function execute_intents. This page covers how intents are structured, wrapped into signed payloads, and the available intent types you can submit.

Ordering and atomicity

Multiple intents can be submitted to execute_intents in a list, where they execute in the order provided.
Important: Because NEAR is an asynchronous and sharded blockchain, intents submitted in sequence do not guarantee they will complete in that sequence. While individual intents execute in order, there is no guarantee that cross-contract calls originating from the Verifier will finish in order.
Example of potential ordering issues:
  1. Intent 1: Perform a storage deposit on usdc.near
  2. Intent 2: Withdraw native NEAR to usdc.near
The usdc.near contract requires a storage deposit before tokens can be deposited. While Intent 1 executes first, there’s no guarantee the storage deposit call will complete before Intent 2’s withdrawal call is made.

Intent structure

Intents are submitted as JSON objects in a payload. Here’s an example Transfer intent for wNEAR tokens from Alice to Bob:
{
  "intent": "transfer",
  "receiver_id": "bob.near",
  "tokens": {
    "nep141:wrap.near": "10"
  }
}
The intent does not mention Alice because the signer of the intent defines which account performs the transfer.

Payload structure

The intent is wrapped in a payload with these required fields:
FieldDescription
signer_idSigner account ID.
verifying_contractContract address receiving the intents.
deadlineTimestamp in ISO 8601 format.
nonce256-bit unique value (see below).
intentsArray of intents to execute.
{
  "signer_id": "alice.near",
  "verifying_contract": "intents.near",
  "deadline": "2025-05-21T12:23:04.252814Z",
  "nonce": "Vij2xgAlKBKzAMcLzEqKQRhRHXp3ThAEFTYtBmfhzvE=",
  "intents": [
    {
      "intent": "transfer",
      "receiver_id": "bob.near",
      "tokens": {
        "nep141:wrap.near": "10"
      }
    }
  ]
}

Nonce structure

The nonce is a 256-bit (32-byte) value encoded as base64. It must be unique per intent to prevent replay attacks. Structure: [4-byte salt][28-byte unique data]
  • Salt (first 4 bytes): Must match the current contract salt (retrieve via simulate_intents)
  • Unique data (remaining 28 bytes): Can be random or sequential, as long as it’s never reused for the same account
The salt rotates periodically. Always fetch the current salt before constructing intents. See the nonce documentation for implementation details.
You can fetch the current salt in two ways:
  1. Via simulate_intents — the response includes the current salt alongside simulation results.
  2. Directly via current_salt — a dedicated view method on the Verifier contract:
cURL
curl -s <NEAR_RPC_URL> \
  -H 'Content-Type: application/json' \
  -d '{
    "jsonrpc": "2.0",
    "id": "dontcare",
    "method": "query",
    "params": {
      "request_type": "call_function",
      "finality": "final",
      "account_id": "intents.near",
      "method_name": "current_salt",
      "args_base64": "e30="
    }
  }' | jq -r '.result.result | implode'
The response is a hex string representing the 4-byte salt prefix, for example "252812b3".

Signed intent format

To create a valid, signed intent for the execute_intents function, wrap the payload in a message string and sign it. See Signing Intents for supported signature types (NEP-413, ERC-191, WebAuthn, and more). Note that the message is the same JSON serialized as a one-liner with escaped quotes:
{
  "standard": "nep413",
  "payload": {
    "recipient": "intents.near",
    "nonce": "Vij2xgAlKBKzgNPJFViEQRiSQad02gXP6pv9IQRCFeg=",
    "message": "{\"deadline\":\"2025-05-21T10:34:04.254392Z\",\"intents\":[{\"intent\":\"transfer\",\"receiver_id\":\"bob.near\",\"tokens\":{\"nep141:usdc.near\":\"10\"}}],\"signer_id\":\"alice.near\"}"
  },
  "public_key": "ed25519:C3jXhkGhEx88Gj7XKtUziJKXEBMRaJ67bWFkxJikVxZ2",
  "signature": "ed25519:2o7Cg7N8bEAKtEDbC9Nja8Ks1bJ9Nunh5Ems51G8oV6n96ckUVFeT81vr3TouE47R24HJSrLyxdeBEbvWeuizVBZ"
}
The recipient field prevents replay attacks on other copies of the Verifier.
All signed examples on this page use the same test key (ed25519:C3jX...). In production, each signer uses their own key pair.

Available intent types

The following intents can be submitted to the Verifier contract.
Rust PascalCase names are converted to snake_case in JSON. For example, TokenDiff becomes token_diff.

add_public_key

Adds a public key to an account in the Verifier contract. The added key’s private key can sign intents on behalf of this account, including adding new keys.
Implicit account IDs have their corresponding public keys added by default. If a private key is leaked for an implicit account, you must manually rotate the public key in the Verifier.
Public keys can also be added via transactions.
ParameterDescription
public_keyThe public key to add to the account (e.g., ed25519:...).
{
  "intent": "add_public_key",
  "public_key": "ed25519:5TagutioHgKLh7KZ1VEFBYfgRkPtqnKm9LoMnJMJugxm"
}
The message field contains the intent JSON above, serialized as a single line with escaped quotes.
[
  {
    "standard": "nep413",
    "payload": {
      "recipient": "intents.near",
      "nonce": "Vij2xgAlKBKzwKyKBC58QRjK3paApkNO6LU77m306Vw=",
      "message": "{\"deadline\":\"2025-05-21T08:04:27.483198Z\",\"intents\":[{\"intent\":\"add_public_key\",\"public_key\":\"ed25519:5TagutioHgKLh7KZ1VEFBYfgRkPtqnKm9LoMnJMJugxm\"}],\"signer_id\":\"alice.near\"}"
    },
    "public_key": "ed25519:C3jXhkGhEx88Gj7XKtUziJKXEBMRaJ67bWFkxJikVxZ2",
    "signature": "ed25519:M6gK8WMNBL9vnkuScshNuKF5Yro5gQNRLpTTbruadR54AQvi53xWw8NizyCRbdM3j6y9XZ7MJy4DtQ1JLDz4xGQ"
  }
]

remove_public_key

Removes a public key from an account. Can also be done via transactions.
ParameterDescription
public_keyThe public key to remove from the account.
{
  "intent": "remove_public_key",
  "public_key": "ed25519:5TagutioHgKLh7KZ1VEFBYfgRkPtqnKm9LoMnJMJugxm"
}
The message field contains the intent JSON above, serialized as a single line with escaped quotes.
[
  {
    "standard": "nep413",
    "payload": {
      "recipient": "intents.near",
      "nonce": "Vij2xgAlKBKzAAxeFUp9QRi4FmMX9Jj6kmrjkUTtltk=",
      "message": "{\"deadline\":\"2025-05-21T08:24:47.536976Z\",\"intents\":[{\"intent\":\"remove_public_key\",\"public_key\":\"ed25519:5TagutioHgKLh7KZ1VEFBYfgRkPtqnKm9LoMnJMJugxm\"}],\"signer_id\":\"alice.near\"}"
    },
    "public_key": "ed25519:C3jXhkGhEx88Gj7XKtUziJKXEBMRaJ67bWFkxJikVxZ2",
    "signature": "ed25519:3E11skwith3ub3w22FnUdcqYzDFy698qBnP8FEPjZyZKbFtqUZK17AXGSLiwnHXppGrV8wbbGafX8fqXUvefoE8p"
  }
]

transfer

Transfers tokens from the signer to a specified account within the Verifier contract. Transfers can also be done via direct blockchain transactions.
ParameterDescription
receiver_idThe account to receive the tokens.
tokensMap of token IDs to amounts in Multi Token format.
memoOptional memo for the transfer.
{
  "intent": "transfer",
  "receiver_id": "bob.near",
  "tokens": {
    "nep141:usdc.near": "10"
  }
}
The message field contains the intent JSON above, serialized as a single line with escaped quotes.
[
  {
    "standard": "nep413",
    "payload": {
      "recipient": "intents.near",
      "nonce": "Vij2xgAlKBKzgNPJFViEQRhm1GXQz/Vt+TS0PazCsJQ=",
      "message": "{\"deadline\":\"2025-05-21T10:34:04.254392Z\",\"intents\":[{\"intent\":\"transfer\",\"receiver_id\":\"bob.near\",\"tokens\":{\"nep141:usdc.near\":\"10\"}}],\"signer_id\":\"alice.near\"}"
    },
    "public_key": "ed25519:C3jXhkGhEx88Gj7XKtUziJKXEBMRaJ67bWFkxJikVxZ2",
    "signature": "ed25519:4nY7kjYV11djwsZ9UmezX1eoVMnzTg2wN6jT67o5vyWnibQ7g34zti8wc9imafbAzH5v4rqmksiextQCas14uxm5"
  }
]

Withdrawal intents

These intents move tokens from the Verifier contract to an arbitrary address: See Withdrawals for details.
ParameterDescription
tokenThe token contract to withdraw (e.g., usdc.near). No prefix for this field.
receiver_idThe NEAR account that will receive the withdrawn tokens.
amountThe amount in the token’s smallest unit.
memoOptional memo for the withdrawal.
msgOptional message to pass to ft_transfer_call. If omitted, ft_transfer is used instead. See Withdrawals for refund behavior.
storage_depositOptional wNEAR amount to pay for storage deposit on the token contract for the receiver. Will not be refunded on failure.
Example: Withdraw from Alice’s account to Bob’s account. On success, the tokens will be in the usdc.near contract under Bob’s account—they have exited the Verifier:
{
  "intent": "ft_withdraw",
  "token": "usdc.near",
  "receiver_id": "bob.near",
  "amount": "1000"
}
The message field contains the intent JSON above, serialized as a single line with escaped quotes.
[
  {
    "standard": "nep413",
    "payload": {
      "recipient": "intents.near",
      "nonce": "Vij2xgAlKBKzgNPJFViEQRiRYtwetaXk8zFqV//Lq3c=",
      "message": "{\"deadline\":\"2025-05-21T10:45:30.098925Z\",\"intents\":[{\"intent\":\"ft_withdraw\",\"token\":\"usdc.near\",\"receiver_id\":\"bob.near\",\"amount\":\"1000\"}],\"signer_id\":\"alice.near\"}"
    },
    "public_key": "ed25519:C3jXhkGhEx88Gj7XKtUziJKXEBMRaJ67bWFkxJikVxZ2",
    "signature": "ed25519:XYNGWVRyGFGRVZAAn62k9r8qthzbj4a5Ct9eCjrSUW9hXpPRaBvqpLKXpaeBgsekfLFiTLdXMEitrbsZAmMmdmU"
  }
]

storage_deposit

Makes an NEP-145 storage_deposit call for an account_id on a contract_id. The amount is subtracted from the user’s NEP-141 wNEAR balance and will not be refunded.
ParameterDescription
contract_idThe contract to make the storage deposit on (e.g., usdc.near).
account_idThe account to deposit storage for.
amountThe wNEAR amount in yoctoNEAR. Subtracted from the signer’s wNEAR balance and will not be refunded.
Example: Pay for storage deposit in the usdc.near contract. The NEAR token specified will be taken from alice.near’s account and paid to bob.near in the usdc.near contract:
{
  "intent": "storage_deposit",
  "contract_id": "usdc.near",
  "account_id": "bob.near",
  "amount": "1250000000000000000000"
}
The message field contains the intent JSON above, serialized as a single line with escaped quotes.
[
  {
    "standard": "nep413",
    "payload": {
      "recipient": "intents.near",
      "nonce": "Vij2xgAlKBKzgNPJFViEQRhA/qs878LtXEL9iIjJC14=",
      "message": "{\"deadline\":\"2025-05-21T11:06:28.803408Z\",\"intents\":[{\"intent\":\"storage_deposit\",\"contract_id\":\"usdc.near\",\"account_id\":\"bob.near\",\"amount\":\"1250000000000000000000\"}],\"signer_id\":\"alice.near\"}"
    },
    "public_key": "ed25519:C3jXhkGhEx88Gj7XKtUziJKXEBMRaJ67bWFkxJikVxZ2",
    "signature": "ed25519:4rAYXBa9UY6Zw32dKcGrXgydParzzdygEwdAaaKRg9TxXSP9541rikLWhVCtJqFHJh4Rcvpp2YrbRQ4LBaay7Xa6"
  }
]

token_diff

The user declares willingness to have a set of changes applied to their tokens. For example, a trade of 100 token A for 200 token B can be represented as {"A": -100, "B": 200}. The Verifier resolves matching diffs into transfers between parties.
When token_diff intents are submitted together in a batch, the total diffs across all intents must sum to zero for each token. If the amounts don’t balance, the entire batch will fail. For example, if Alice gives 10 USDC, another intent in the batch must receive exactly 10 USDC.
ParameterDescription
diffMap of token IDs to signed amount strings. Negative values indicate tokens given, positive values indicate tokens received.
memoOptional memo for the trade.
referralOptional account ID for referral tracking.
Example: Two users trading USDC for USDT. Alice declares she’ll give up 10 USDC to get 10 USDT; Bob declares the opposite. These intents can be matched through the Message Bus or any off-chain channel, then submitted together:
{
  "intent": "token_diff",
  "diff": {
    "nep141:usdc.near": "-10",
    "nep141:usdt.near": "10"
  }
}
The message field contains the intent JSON above, serialized as a single line with escaped quotes.
[
  {
    "standard": "nep413",
    "payload": {
      "recipient": "intents.near",
      "nonce": "Vij2xgAlKBKzgMh0PGuHQRiOD4cMhPLCgZfb8bCmR7s=",
      "message": "{\"deadline\":\"2025-05-21T11:30:25.042157Z\",\"intents\":[{\"intent\":\"token_diff\",\"diff\":{\"nep141:usdc.near\":\"-10\",\"nep141:usdt.near\":\"10\"}}],\"signer_id\":\"alice.near\"}"
    },
    "public_key": "ed25519:C3jXhkGhEx88Gj7XKtUziJKXEBMRaJ67bWFkxJikVxZ2",
    "signature": "ed25519:2tKuCpxqtx6YUY6LRkQGeqmAizA8CKhkFtYdsHsAGRjwm4tFcPHHhBRGtuQAAbAkUkwJ6n2UptTP4Mpot1cTvf2u"
  },
  {
    "standard": "nep413",
    "payload": {
      "recipient": "intents.near",
      "nonce": "Vij2xgAlKBKzgMh0PGuHQRhE5M+mHoAocV57AzeIPuQ=",
      "message": "{\"deadline\":\"2025-05-21T11:30:25.054132Z\",\"intents\":[{\"intent\":\"token_diff\",\"diff\":{\"nep141:usdc.near\":\"10\",\"nep141:usdt.near\":\"-10\"}}],\"signer_id\":\"bob.near\"}"
    },
    "public_key": "ed25519:C3jXhkGhEx88Gj7XKtUziJKXEBMRaJ67bWFkxJikVxZ2",
    "signature": "ed25519:gTrJn3CaESvDJ765SDZ7JdkXupeGApjU6t66XpwrCXKM5K7b4VEeZXxL6NSL7i5zJ2Dn1aracg9xubktcPLwHEq"
  }
]
As described in the Introduction, there are many ways to bundle these intents together for submission—the Message Bus, third parties, or any off-chain communication channel.

Next steps