near_dart 0.2.2 copy "near_dart: ^0.2.2" to clipboard
near_dart: ^0.2.2 copied to clipboard

Complete NEAR Protocol SDK for Flutter/Dart. RPC client, wallet integration, and type-safe primitives.

near_dart #

Complete NEAR Protocol SDK for Flutter/Dart.

pub package License: MIT

A type-safe, platform-agnostic SDK for building NEAR Protocol applications with Flutter and Dart. Works on iOS, Android, Web, and Desktop.

NEAR Flutter SDK demo on Android

The example app — local Sign & Send and wallet connect — running on Android.

Features #

  • Local Signing & Sending: ed25519 key pairs, Borsh serialization, send_tx broadcasting — byte-for-byte compatible with near-api-js
  • High-Level Account API: transfer() / callFunction() in one call (nonce + block hash resolved automatically)
  • RPC Client: Query blockchain state, accounts, contracts, and validators — FastNear endpoints by default, automatic failover
  • Wallet Integration: Connect wallets via WalletConnect or deep links
  • Type-Safe Primitives: AccountId, NearToken, PublicKey, CryptoHash
  • Transaction Building: All NEAR actions, including NEP-591 Global Contracts
  • NEP-413 Support: Message signing for authentication
  • Tested against the real chain: every release runs a real sign-and-send E2E on testnet

Installation #

dependencies:
  near_dart: ^0.2.0

Quick Start #

import 'package:near_dart/near_dart.dart';

void main() async {
  // Create client (mainnet or testnet)
  final client = NearRpcClient.mainnet();

  // Get network status
  final status = await client.status();
  switch (status) {
    case RpcSuccess(:final value):
      print('Chain: ${value.chainId}');
      print('Block: ${value.syncInfo.latestBlockHeight}');
    case RpcFailure(:final error):
      print('Error: ${error.message}');
  }

  // Query account
  final result = await client.viewAccount(
    accountId: AccountId('alice.near'),
    blockReference: BlockReference.finality(Finality.final_),
  );

  if (result.isSuccess) {
    final account = result.getOrNull()!;
    print('Balance: ${account.amount.toNear()} NEAR');
  }

  client.close();
}

Sign & Send Transactions (local keys) #

The fastest way to execute transactions — no wallet redirect needed:

import 'package:near_dart/near_dart.dart';

void main() async {
  final client = NearRpcClient.testnet();

  final account = Account(
    accountId: AccountId('alice.testnet'),
    keyPair: await KeyPairEd25519.fromString('ed25519:<your secret key>'),
    client: client,
  );

  // Transfer NEAR
  final result = await account.transfer(
    receiverId: AccountId('bob.testnet'),
    amount: NearToken.fromNear(1),
  );

  switch (result) {
    case RpcSuccess(:final value):
      print('Executed! https://testnet.nearblocks.io/txns/${value.transaction.hash}');
    case RpcFailure(:final error):
      print('Failed: ${error.message}');
  }

  // Call a contract method that changes state
  await account.callFunction(
    contractId: AccountId('wrap.testnet'),
    methodName: 'near_deposit',
    deposit: NearToken.fromNear(1),
  );

  client.close();
}

Need lower-level control? Sign and broadcast manually:

final signed = await signTransaction(
  Transaction(
    signerId: AccountId('alice.testnet'),
    receiverId: AccountId('bob.testnet'),
    nonce: nonce,                 // access key nonce + 1
    blockHash: recentBlockHash,   // from viewAccessKey or block()
    actions: [TransferAction(deposit: NearToken.fromNear(1))],
  ),
  keyPair,
);
print(signed.hash);               // transaction hash (base58)
await client.sendTransaction(signed, waitUntil: TxExecutionStatus.final_);

Serialization and signatures are validated byte-for-byte against canonical near-api-js vectors, and the full pipeline runs end-to-end against real testnet in CI.

RPC Client #

Network Status #

final result = await client.status();

Account Information #

final result = await client.viewAccount(
  accountId: AccountId('alice.near'),
  blockReference: BlockReference.finality(Finality.final_),
);

Call Contract View Function #

final result = await client.callFunction(
  accountId: AccountId('token.near'),
  methodName: 'ft_balance_of',
  args: {'account_id': 'alice.near'},
  blockReference: BlockReference.finality(Finality.final_),
);

if (result.isSuccess) {
  final balance = result.getOrNull()!.resultAsJson();
  print('Token balance: $balance');
}

Validators #

final result = await client.validators();
if (result.isSuccess) {
  final validators = result.getOrNull()!;
  print('Current validators: ${validators.currentValidators.length}');
}

Wallet Integration #

Building Transactions #

// Simple transfer
final tx = Transaction(
  signerId: AccountId('alice.near'),
  receiverId: AccountId('bob.near'),
  actions: [
    TransferAction(deposit: NearToken.fromNear(1)),
  ],
);

// Contract function call
final tx = Transaction(
  signerId: AccountId('alice.near'),
  receiverId: AccountId('token.near'),
  actions: [
    FunctionCallAction(
      methodName: 'ft_transfer',
      args: {'receiver_id': 'bob.near', 'amount': '1000000'},
      deposit: NearToken.oneYocto(),
    ),
  ],
);

Action Types #

CreateAccountAction()
DeployContractAction(code: wasmBytes)
FunctionCallAction(methodName: 'method', args: {...}, deposit: NearToken.zero())
TransferAction(deposit: NearToken.fromNear(10))
StakeAction(stake: NearToken.fromNear(100), publicKey: PublicKey('ed25519:...'))
AddKeyAction(publicKey: key, accessKey: FullAccessKey())
DeleteKeyAction(publicKey: key)
DeleteAccountAction(beneficiaryId: AccountId('beneficiary.near'))

MyNearWallet Integration (connect once, then sign locally) #

signIn() generates a function-call key, redirects to MyNearWallet to provision it, and completeSignIn() stores the private key — so afterward you call contracts locally, with no more redirects.

final adapter = MyNearWalletAdapter(
  config: MyNearWalletConfig(
    contractId: AccountId('app.near'),
    successUrl: 'myapp://callback/success',   // https URL on web
    failureUrl: 'myapp://callback/failure',
    network: MyNearWalletNetwork.mainnet,
  ),
  // Persist keys across the redirect/restarts (see the example app's
  // SharedPrefsKeyStore). Defaults to InMemoryKeyStore.
  keyStore: myPersistentKeyStore,
  launchUrl: (uri) => launchUrl(uri, mode: LaunchMode.externalApplication),
);

// 1. Connect: generates a key and redirects to the wallet.
await adapter.signIn(contractId: AccountId('app.near'));

// 2. When the wallet redirects back (deep link on mobile, app URL on web):
final account = await adapter.completeSignIn(callbackUri);
print('Connected: ${account?.accountId}');

// 3. From now on, sign contract calls locally — no redirect:
final near = Account(
  accountId: account!.accountId,
  keyPair: (await adapter.keyFor(account.accountId))!,
  client: NearRpcClient.mainnet(),
);
await near.callFunction(
  contractId: AccountId('app.near'),
  methodName: 'set_greeting',
  args: {'greeting': 'hola'},
);

Type-Safe Primitives #

AccountId #

final account = AccountId('alice.near');  // Validates format

NearToken #

final amount = NearToken.fromNear(10);     // 10 NEAR
final small = NearToken.oneYocto();        // 1 yoctoNEAR
final zero = NearToken.zero();
print(amount.toNear());  // 10.0

PublicKey #

final key = PublicKey('ed25519:6E8sCci9badyRkXb3JoRpBj5p8C6Tw41ELDZoiihKEtp');
print(key.keyType);  // KeyType.ed25519

BlockReference #

BlockReference.finality(Finality.final_)  // Latest finalized
BlockReference.finality(Finality.optimistic)  // Latest (may reorg)
BlockReference.blockId(123456789)  // Specific height
BlockReference.blockHash(CryptoHash('...'))  // Specific hash

Error Handling #

final result = await client.viewAccount(...);

switch (result) {
  case RpcSuccess(:final value):
    print('Balance: ${value.amount.toNear()}');
  case RpcFailure(:final error):
    switch (error.kind) {
      case RpcErrorKind.rpcError:
        print('RPC error: ${error.message}');
      case RpcErrorKind.networkError:
        print('Network error');
      case RpcErrorKind.timeout:
        print('Request timeout');
      default:
        print('Error: ${error.message}');
    }
}

Example App #

See the example directory for a complete Flutter app demonstrating every SDK feature: local Sign & Send, wallet connect (redirect + deep link), and all RPC queries — with network switching between testnet and mainnet.

Verified on real devices & chains #

Recorded evidence from the example app running against real NEAR testnet (no mocks at any layer):

Demo Evidence On-chain proof
Android: generate key → faucet → sign & send on-chain video / gif JByxPfTt…34cZG
Android: wallet connect → browser → nearsdk:// deep link → connected video / gif function-call key provisioning flow

Additionally verified: web (Chrome, dart2js and dart2wasm — byte-identical signatures vs near-api-js), real on-chain transfers from the browser, and a scheduled CI E2E that signs and sends a real testnet transaction. iOS builds are verified on every push via a macOS CI job.

Testing #

dart test --exclude-tags integration   # 394 offline tests (no network)
dart test test/integration/testnet/    # live testnet RPC tests
dart test test/e2e/                    # incl. a REAL sign+send on testnet

Serialization and signatures are validated byte-for-byte against canonical near-api-js@7.2.0 vectors (test/fixtures/near_api_js_vectors.json).

License #

MIT License - see LICENSE for details.

0
likes
160
points
86
downloads

Documentation

API reference

Publisher

verified publisher0xj.dev

Weekly Downloads

Complete NEAR Protocol SDK for Flutter/Dart. RPC client, wallet integration, and type-safe primitives.

Homepage
Repository (GitHub)
View/report issues

Topics

#near #blockchain #web3 #crypto #wallet

License

MIT (license)

Dependencies

crypto, cryptography, equatable, http, meta

More

Packages that depend on near_dart