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

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
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:
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.
The message field contains the intent JSON above, serialized as a single line with escaped quotes.

remove_public_key

Removes a public key from an account. Can also be done via transactions.
The message field contains the intent JSON above, serialized as a single line with escaped quotes.

transfer

Transfers tokens from the signer to a specified account within the Verifier contract. Transfers can also be done via direct blockchain transactions.
The message field contains the intent JSON above, serialized as a single line with escaped quotes.

Withdrawal intents

These intents move tokens from the Verifier contract to an arbitrary address: See Withdrawals for details. 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:
The message field contains the intent JSON above, serialized as a single line with escaped quotes.

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. 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:
The message field contains the intent JSON above, serialized as a single line with escaped quotes.

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.
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:
The message field contains the intent JSON above, serialized as a single line with escaped quotes.
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

Signing Intents

Learn how to sign intents for different wallet types

Simulating Intents

Test intents before submitting them on-chain

Deposits & Withdrawals

Deposit and withdraw tokens from the Verifier

Events

Monitor intent execution via on-chain events