Token standards
Fungible tokens (NEP-141)
NEP-141 is the ERC-20 of NEAR — but there is no approve/allowance. ft_transfer_call does an atomic transfer-and-call instead.
NEP-141 is NEAR’s fungible-token standard — the ERC-20 equivalent. The interface looks familiar, with one big omission: there is no `approve` / `allowance` / `transferFrom`. Instead, ft_transfer_call transfers to a contract and calls it in one atomic step.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
interface IERC20 {
function totalSupply() external view returns (uint256);
function balanceOf(address account) external view returns (uint256);
function transfer(address to, uint256 amount) external returns (bool);
// the allowance dance — a spender you pre-approve
function approve(address spender, uint256 amount) external returns (bool);
function allowance(address owner, address spender) external view returns (uint256);
function transferFrom(address from, address to, uint256 amount)
external returns (bool);
}use near_sdk::json_types::U128;
use near_sdk::{AccountId, PromiseOrValue};
// NEP-141 core (near-contract-standards: FungibleTokenCore)
pub trait FungibleTokenCore {
fn ft_transfer(&mut self, receiver_id: AccountId, amount: U128, memo: Option<String>);
// transfer to a CONTRACT and call its ft_on_transfer in one atomic step;
// the receiver returns how much to refund. Replaces approve + transferFrom.
fn ft_transfer_call(
&mut self,
receiver_id: AccountId,
amount: U128,
memo: Option<String>,
msg: String,
) -> PromiseOrValue<U128>;
fn ft_total_supply(&self) -> U128;
fn ft_balance_of(&self, account_id: AccountId) -> U128;
}No approve / allowance / transferFrom. ft_transfer_call atomically moves tokens to a contract and invokes its ft_on_transfer(sender, amount, msg), which returns the unused amount to refund — killing the infinite-approval footgun.
ft_transfer requires exactly 1 yoctoNEAR attached (a confirmation that the key really meant to move funds), and receivers must be registered for storage first (NEP-145) so their balance entry has a paid slot.
You rarely write this by hand: near-contract-standards provides a FungibleToken you embed, then one macro implements the whole standard — metadata is NEP-148.