execute_intents call submits on-chain.
Architecture overview
Two input formats, one chain identity
NEAR carries two distinct payload shapes under a singleCHAIN_NEAR identity, discriminated purely by input format:
- A borsh-encoded transaction (
near::sign_transaction) — the standard NEAR wire format (near_primitives::transaction::TransactionorSignedTransaction), hex or base64 encoded. - A pre-signature intents envelope (
near::sign_intent) — a bareDefusePayloadJSON object, the message a user signs before it is wrapped in a signature standard and submitted to solvers.
Account model
NEAR is account-based. Accounts are either named (alice.near) or implicit — derived deterministically from a public key, with no on-chain registration step. HSM-generated keys always produce implicit accounts: a 64-character hex string for ed25519 keys, an EVM-style 0x… address for secp256k1 keys. A single user signing on multiple chains therefore appears as multiple, unlinked implicit accounts on intents.near — one per key.
Key components
For a borsh transaction, the parser produces:- Top-level fields:
Network,From,To. - Per-action fields — a native
Transferrenders anAmount; aFunctionCallrendersMethodplus, for the three token-movement methods the parser understands (ft_transfer,ft_transfer_call,ft_withdraw), the resolved recipient and amount. Anexecute_intentscall tointents.nearadditionally decodes and renders the full signed intent batch inline. Any other action or method renders its generic label only — a partially understood call never masquerades as a fully decoded one.
execute_intents batch), the parser produces:
- Envelope fields:
Signer,Verifying Contract,Deadline,Nonce. A pre-signature envelope is preceded by the sameNetworkfield the borsh path renders, since the resolved network is part of every token-metadata signature scope. - For a signed batch specifically, a
StandardandSignature(or a signature-invalid warning) per entry, since verification and structural decode are independent — a bad signature still renders the intents it wraps. - Per-intent fields, one section per intent in the batch.
Supported intent types
ft_withdraw, nft_withdraw, and mt_withdraw each carry an optional storage_deposit (a second, unconditional wNEAR debit alongside the withdrawal, never refunded on failure) and msg (which switches the call into its _transfer_call form) — both render when present, since either changes what the withdrawal actually does beyond moving the named asset.
Signature standards
The intents preset verifies all seven signature standards the protocol defines — NEP-413, ERC-191, TIP-191, raw ed25519, WebAuthn, TonConnect, and SEP-53 — using the protocol’s own canonical implementation (near/intents) rather than a reimplementation, so new intent variants and signing standards stay correct as the protocol evolves. Verification recovers a signing key; whether that key is checked against the claimed account depends on the account’s shape. For an implicit account, the account id is itself derived from the key, so the recovered key is compared against it directly — a mismatch renders as a hard finding, not a hedge. For a named account (alice.near), that key-to-account relationship lives in on-chain access-key state the parser doesn’t have, so it renders as an explicit “not verified” caveat instead.
ERC-191 and TIP-191 recover a secp256k1 key rather than pass/fail: a well-formed signature always recovers some key, so a tampered message recovers a different key rather than failing outright. A malformed recovery byte is rejected before it reaches verification, since the native ecrecover backend otherwise panics on out-of-range input — a malformed payload must be treated as invalid input, never a crash.
Visualization strategy
- Amounts in native units where resolvable — a
wrap.near(wNEAR) transfer renders as1 wNEAR, not1000000000000000000000000raw units. Unresolved assets render the raw base-unit amount tagged with the asset id, rather than guessing at decimals — a wrong decimals value would silently misrender an amount. Beyond the compiled-in seed table, a wallet can supply symbol/decimals for additional asset ids per request, optionally signed by a curator key whose curve is chosen by the asset’s origin chain (NEAR, Ethereum, or Solana) rather than a single NEAR-wide curve — see Chain Metadata. - Fail-closed method-args decoding —
ft_transfer,ft_transfer_call, andft_withdrawargs decode only when they parse as exactly the known shape (deny_unknown_fields); anything else falls back to the genericFunctionCallview rather than rendering a partial, possibly misleading subset of fields. - Deadlines and invalid signatures render as soft findings alongside the content they qualify — the intents still render even when a deadline has passed or a signature fails verification, with the problem surfaced as a warning field rather than blocking the render outright.
Using parser_cli
The CLI accepts either input format directly — hex/base64 for a transaction, or raw JSON for an intents envelope:--network flag selects the rendered Network header — NEAR_MAINNET (the default) or NEAR_TESTNET. An unrecognized value errors before anything renders, rather than silently falling back to mainnet.
The resolved network also has to agree with the accounts being rendered: an account whose suffix contradicts it (.testnet under mainnet, or .near under testnet) is refused rather than displayed under a network it does not belong to. This covers the transaction’s own accounts and every rendered envelope’s signer_id/verifying_contract. Since the default is mainnet, decoding a .testnet envelope needs --network NEAR_TESTNET explicitly. Implicit (64-hex) accounts carry no suffix and are not constrained.
Supplying token metadata locally
Assets the compiled-in seed table doesn’t cover render their raw base-unit amount taggedunresolved <asset id>. To give the CLI a symbol and decimals for one, pass --near-token-metadata-mappings:
my-token.near, the asset the mapping covers, so the
Amount field renders as 1 MYTOKEN rather than 100000000 (unresolved nep141:my-token.near).
Two details differ from the Ethereum and Solana mapping flags:
@separates the fields, not:. NEAR Intents asset ids contain their own colons (nep141:wrap.near), so a colon-delimited format would truncate the id at its first embedded colon.- The CLI signs each entry it loads with its local development key, because it runs the require-signed posture — an unsigned entry is dropped rather than trusted. That key is allowlisted only in builds that enable the
dev-signingfeature, whichparser_clidoes and the enclave binary does not. The posture is a per-deployment choice, not a property of the parser:parser_clipins require-signed, whileparser_appregisters the converter with the permissive default.
Configuring curator keys
Signer identity is resolved per origin chain from three environment variables, each a comma-separated list of hex public keys:
Each populates only its own domain, so a key trusted for Ethereum-origin assets does not thereby vouch for NEAR-native ones. A variable left unset leaves that domain with no enrolled curators, and a signature checked against it is never recognized.
An unset domain is fail-closed but not inert: under the permissive posture the entry is still accepted as a gap fill for an asset the seed table does not cover, and marked unverified. It cannot override a curated seed. Under the require-signed posture it is refused outright. So a deployment that wants signed token metadata to count as verified has to enrol the curator keys; without them, supplying a signature has the same effect as omitting one.