NEAR Protocol kit for Android, in the style of the other HorizontalSystems *-kit-android
libraries. It derives keys, syncs balance, tokens and history, and signs and submits
transactions without any third-party NEAR SDK.
- Keys. Ed25519 at SLIP-10
m/44'/397'/0'from a BIP39 seed, the path near-seed-phrase (MyNearWallet, near-cli) and Trust Wallet use, so the same words give the same key everywhere. Ledger uses44'/397'/0'/0'/1', a different key.ed25519:…secret keys import too. - Accounts. The key's implicit account (64 hex characters) by default, or a named account
(
alice.near) the key controls.NearKit.findAccountslists both, confirming each named account on chain. - Sync. Latest block and gas price,
view_account, token balances and history, polled over JSON-RPC with endpoint failover. The RPC has no per-account history or token list, so those come from the FastNEAR indexer. - Balance.
availableBalanceis the balance minus storage staking. Accounts using up to 770 bytes need none (NEP-448); above that the whole usage is staked at 10^19 yocto per byte. - Tokens. NEP-141 balances,
ft_metadata, and transfers that include the receiver's NEP-145 storage deposit when it is not registered yet. The token contract sets that deposit, so it is capped at 0.1 NEAR, andsendFtrefuses to send when it differs from the confirmed estimate. History reads NEP-297 events and the plain-text logs of older contracts such as wrap.near. - Sending. Transactions are Borsh-encoded, and the SHA-256 hash is signed with Ed25519.
They are submitted with
send_txand tracked from pending to final. A pending send that no node knows once its block hash expires is marked failed. - Fees. Two numbers from the runtime config:
feeis what the send finally costs.requiredBalanceis what the account must hold up front. Gas is bought at no less thanmin_gas_purchase_price(10× the usual gas price) and partly refunded.- A transfer to an implicit account always pays account-creation gas, and one that creates the account also pays the 0.007 NEAR creation charge.
val seed = Mnemonic().toSeed(words)
val accounts = NearKit.findAccounts(NearKit.publicKey(seed), Network.MainNet) // implicit first
val kit = NearKit.getInstance(context, NearWallet.Seed(seed, accounts.first()), Network.MainNet, walletId = "wallet-1")
kit.watchTokens(setOf("usdt.tether-token.near"))
kit.start()
kit.accountStateFlow.collect { state -> /* amount, available, storageUsage (yoctoNEAR) */ }
kit.ftBalancesFlow.collect { balances -> /* contractId, balance in the token's smallest unit */ }
kit.transactionsFlow.collect { changed -> /* new or updated Transaction records */ }
val estimate = kit.estimateNearTransfer(to) // fee, requiredBalance
val max = kit.maxSendableNear(to)
val tx = kit.sendNear(to, NearAmount.toYocto(BigDecimal("1.5")))
val ftEstimate = kit.estimateFtTransfer("usdt.tether-token.near", to, BigInteger("1000000"))
// show ftEstimate.storageDeposit to the user, then pass the confirmed estimate
val ftTx = kit.sendFt("usdt.tether-token.near", to, BigInteger("1000000"), estimate = ftEstimate)Watch-only: NearWallet.WatchOnly("alice.near"). Sends then throw NearKit.WalletError.WatchOnly.
History per asset: kit.getTransactions(token = NearKit.TOKEN_NATIVE) or
kit.getTransactions(token = "usdt.tether-token.near"), paged by the timestamp and hash of the
last item. A Transaction carries the account's NEAR movements (nearTransfers,
nearNetChange) and token movements (ftTransfers) found anywhere in its receipt tree.
For dApps and swaps: sendTransaction(receiverId, actions), signTransaction(...), submit(signed),
and Transaction.decode / SignedTransaction.decode for Borsh payloads a dApp hands over.
signMessage(MessagePayload(...)) signs NEP-413 messages (near_signMessage); the kit never signs
raw bytes, since a dApp could pass a transaction hash as the "message".
A send fails with SendError.Rejected only when no node knows the transaction. Any other error
may come after it reached the chain, so it stays in history as pending until it resolves or
expires; show it rather than offering to send again.
| Package | Contents |
|---|---|
crypto |
Base58, account id rules, Ed25519 public key |
borsh |
Borsh writer and reader |
transaction |
Actions, Transaction/SignedTransaction codec, Signer, FeeCalculator, FtActions, TransactionSender |
network |
JSON-RPC provider with failover, FastNEAR client, connectivity |
sync |
Timer, account/token syncer, history syncer, receipt-tree converter |
database |
Room storage, one database per wallet id |
./gradlew :nearkit:testDebugUnitTest
Offline tests check the kit against reference output:
- Keys against
near-seed-phrase. - Transaction bytes, hashes and signatures against
@near-js/transactions2.5.1. - The converter against real mainnet and testnet transactions from FastNEAR and the RPC.
The live tests run with NEARKIT_INTEGRATION=true:
MainnetReadTest: every RPC endpoint, the token list, history and account discovery.TestnetIntegrationTest: creates a funded account through the testnet helper, sends NEAR to a new implicit account, checks that a stale nonce is refused, then wraps NEAR and sends the token with a storage deposit. It then finds all of it in the index.NearKitRobolectricTest: the whole kit with Room and the sync timer: a watch-only mainnet sync, and a testnet send tracked from pending to final to indexed.
The app module is a sample. You can restore a mnemonic or secret key, pick an account, create a
funded .testnet account, send NEAR or a token, and see history.
NEP-413 message signing (WalletConnect near_signMessage), staking pools, NEP-245 multi-tokens
(NEAR Intents balances), NFTs, delegate actions (meta transactions), and Ledger's derivation path.