Constructing a transaction

Build, preview, and send — no BigInt.

A NEAR transaction is a receiverId plus an ordered list of actions. With @fastnear/api you declare the actions, preview them, and sign from a wallet or a local key. There is one rule to learn, and it removes the whole class of big-number snags: you pass amounts in whatever form is handy, and you always get decimal strings back.

The one rule
  • In: gas, deposits, and amounts accept a string, number, or bigint — plus readable unit strings like "100 Tgas" and "0.01 NEAR".
  • Out: wide integers (u64/u128 — amounts, gas, nonces) come back as decimal strings, JSON-safe and matching NEAR RPC.
  • Inspect a transaction with near.explain.tx(...) or near.utils.txToJson(...) — never JSON.stringify a raw bigint (it throws).
  • You never need BigInt to build, send, or read a transaction.
Declare + preview

near.explain.tx is a pure function — it returns a JSON-safe summary of exactly what you are about to sign, with no network call and no wallet popup.

// One action: draw a green pixel on berryclub.ek.near.
const actions = [
  near.actions.functionCall({
    methodName: "draw",
    args: { pixels: [{ x: 10, y: 20, color: "00FF00" }] },
    gas: "100 Tgas",      // or 100000000000000, or 100000000000000n
    deposit: "0.01 NEAR", // or a yocto string like "10000000000000000000000"
  }),
];

// Preview before signing — JSON-safe, gas/deposit stay as you wrote them.
near.print(near.explain.tx({
  signerId: "alice.near",
  receiverId: "berryclub.ek.near",
  actions,
}));
Sign and send

The same actions, two signers.

Once the actions are declared, sending is one call. In a browser the wallet holds the key; in Node you sign locally with a full-access key. Both accept the identical action shape and the same unit strings.

Browser wallet

After nearWallet.connect(...), the wallet signs. Load the IIFE globals (near.js, wallet.js) or import @fastnear/api + @fastnear/wallet.

// Wallet-signed. Units in, no BigInt — the popup confirms the deposit.
const result = await near.recipes.functionCall({
  receiverId: "berryclub.ek.near",
  methodName: "draw",
  args: { pixels: [{ x: 10, y: 20, color: "00FF00" }] },
  gas: "100 Tgas",
  deposit: "0.01 NEAR",
});

near.print(result); // outcome amounts/gas are decimal strings
Node, local key

Sign with a full-access key from @fastnear/utils. Keep the key in server-side secret storage — never ship it to a browser.

import { actions, config, sendTx } from "@fastnear/api";
import { signerFromPrivateKey } from "@fastnear/utils";

config({ networkId: "mainnet" });

const result = await sendTx({
  signerId: "alice.near",
  signer: signerFromPrivateKey(privateKey), // full-access key
  receiverId: "berryclub.ek.near",
  actions: [
    actions.functionCall({
      methodName: "draw",
      args: { pixels: [{ x: 10, y: 20, color: "00FF00" }] },
      gas: "100 Tgas",
      deposit: "0.01 NEAR",
    }),
  ],
  waitUntil: "FINAL",
});
Wide integers

Big numbers are strings, everywhere.

NEAR amounts exceed Number's safe range, so they are never plain JS numbers. Across @fastnear they are decimal strings on the way out — the same shape NEAR JSON-RPC uses — so a decoded transaction survives JSON.stringify and re-encodes to identical bytes. Reach for BigInt only if you need arithmetic.

What this buys you
  • JSON.stringify(tx) never throws — there is no bigint to trip on.
  • Values from near.view, near.ft.balance, and decoded borsh are all strings, so they interoperate without conversion.
  • Serializing accepts string | number | bigint, so a value you read can be sent straight back.
Decoding borsh yourself?
  • @fastnear/borsh deserialize returns u64/u128 as decimal strings by default.
  • Pass deserialize(schema, bytes, { bigints: "bigint" }) to opt into native bigint when you want arithmetic.
  • u8/u16/u32 stay JS numbers (they fit safely).
Go deeper

AI agents: the "Result shapes" section of llms-full.txt states the wide-integers rule, and recipes.json is the structured task catalog (see the explain-transaction, function-call, and transfer recipes). Rate-limited? Free trial credits are at dashboard.fastnear.com — set near.config({ apiKey }) once you have one.