Skip to main content

A Pythonic SDK for NEAR Protocol. Feels like requests.

Project description

near-kit

CI codecov PyPI version Python 3.11+ License: MIT

A Pythonic SDK for NEAR Protocol. Feels like requests.

import near

near.view("counter.near", "get_count")          # one line, no setup
near.balance("alice.near")                       # -> Amount('42.5 NEAR')

Human-readable everywhere — "10 NEAR" and "30 Tgas", never 10000000000000000000000000. Typed errors, exact integer math, sync and async, and post-quantum keys. The Python sibling of near-kit for TypeScript.

Install

uv add near-kit        # or: pip install near-kit

Python 3.11+.

The rule of the API

Reads are stateless; if it signs, you need a client.

Module functions cover one-off reads, requests.get()-style. A Near client holds the stateful things: your signer, a nonce cache, and a connection pool.

from near import Near

# Explicit config...
client = Near(network="testnet",
              account_id="alice.testnet",
              private_key="ed25519:...")

# ...or zero-argument discovery: NEAR_NETWORK / NEAR_ACCOUNT_ID /
# NEAR_PRIVATE_KEY env vars, falling back to ~/.near-credentials.
client = Near()

# ...or straight from NEAR CLI credentials:
client = Near.from_file("alice.testnet", network="testnet")

Reads

client.view("counter.testnet", "get_count")
client.balance()                      # your balance -> Amount
client.balance("bob.testnet")         # anyone's
client.account("bob.testnet")         # AccountView (balance, storage, code hash)
client.account_exists("bob.testnet")
client.access_keys("bob.testnet")
client.transaction_status(tx_hash)
client.rpc("block", {"finality": "final"})   # escape hatch: any RPC method

Writes

client.send("bob.testnet", "5 NEAR")
client.call("counter.testnet", "increment", {"by": 2},
            deposit="0.1 NEAR", gas="30 Tgas")

Multi-action transactions are just data — a list of actions, one receiver, executed atomically:

from near import create_account, transfer, deploy_contract, function_call, add_full_access_key

client.send_transaction(
    "sub.alice.testnet",
    actions=[
        create_account(),
        transfer("5 NEAR"),
        add_full_access_key(key.public_key),
        deploy_contract(wasm_bytes),
        function_call("init", {"owner": "alice.testnet"}),
    ],
)

Tokens

NEP-141 fungible tokens are first-class: amounts are human strings in the token's own decimals, and register=True batches the receiver's storage_deposit into the same atomic transaction when they aren't registered yet.

client.ft_transfer("usdt.tether-token.near", "bob.near", "5.25 USDT", register=True)

balance = client.ft_balance("usdt.tether-token.near")   # TokenAmount, exact int
print(balance)                                          # 5.25 USDT
balance.display                                         # Decimal('5.25')

NFTs (NEP-171) get the same treatment: nft_transfer attaches the required 1 yoctoNEAR, nft_token / nft_tokens_for_owner cover lookups.

Async

AsyncNear is the same surface, awaited — for FastAPI services, relayers, and MCP servers:

from near import AsyncNear

async with AsyncNear() as client:
    await client.call("counter.testnet", "increment")
    results = await asyncio.gather(*(client.send(acc, "0.1 NEAR") for acc in accounts))

Concurrent transactions from one account just work — the client manages nonces and retries collisions automatically.

Amounts are exact

Amount is an int subclass denominated in yoctoNEAR, so arithmetic and comparisons are exact; it parses and prints human strings. Bare numbers are rejected at API boundaries — unit confusion is a bug that should not compile.

from near import Amount

bal = client.balance()          # Amount(5250000000000000000000000)
str(bal)                        # '5.25 NEAR'
bal.as_near                     # Decimal('5.25')
bal > Amount("1 NEAR")          # True
client.send("bob.near", 5)      # UnitParseError: write "5 NEAR" or "5 yocto"

Typed errors

from near import ContractPanicError, AccountNotFoundError

try:
    client.call("app.near", "buy", deposit="1 NEAR")
except ContractPanicError as e:
    print(e.panic)     # the contract's panic message
    print(e.logs)      # contract logs leading up to it

Every error derives from NearError with a stable .code and a .retryable flag.

Testing your app: the sandbox is a database

Run NEAR like you'd run postgres in CI:

docker run -d -p 3030:3030 nearprotocol/sandbox:2.13.1

The sandbox root account's key is deterministic (derived from the image's test seed), so nothing needs to be copied out of the container:

from near import Near
from near.testing import sandbox_signer

near = Near(rpc_url="http://localhost:3030", signer=sandbox_signer())
near.send("anything.sandbox", ...)   # root account, fully funded

GitHub Actions:

services:
  near-sandbox:
    image: nearprotocol/sandbox:2.13.1
    ports: ["3030:3030"]

Or let pytest do all of it — installing near-kit registers a plugin. Its near_sandbox fixture reuses NEAR_SANDBOX_URL or localhost:3030 when reachable, otherwise starts (and later removes) a Docker sandbox on a free port; sandbox_near is a Near client signing as the root account:

from near import add_full_access_key, create_account, generate_key, transfer
from near.testing import fast_forward


def test_my_app(sandbox_near):
    key = generate_key()
    sandbox_near.send_transaction(  # root creates + funds a fresh account
        "alice.sandbox",
        actions=[create_account(), transfer("10 NEAR"), add_full_access_key(key.public_key)],
    )
    fast_forward(sandbox_near, 100)  # time travel: 100 blocks, no waiting

Meta-transactions (NEP-366)

User signs, relayer pays gas:

# User side — no gas spent:
signed = client.sign_delegate("app.near", actions=[function_call("claim", {})])
payload = encode_signed_delegate(signed)          # base64, POST it to your relayer

# Relayer side:
relayer.send_delegate(payload)

Message signing (NEP-413)

Off-chain auth ("login with NEAR"):

signed = client.sign_message("Login to MyApp", recipient="myapp.com")

# Server side:
from near import verify_message
verify_message(signed, "Login to MyApp", "myapp.com", nonce)

Post-quantum keys

ML-DSA-65 (FIPS 204) keys work everywhere ed25519 keys do:

from near import MlDsa65KeyPair

pq = MlDsa65KeyPair.generate()
client.send_transaction(account_id, actions=[add_full_access_key(pq.public_key)])

Custom signers (KMS, HSM)

Anything with account_id, public_key, and sign(message) -> bytes is a signer:

class KmsSigner:
    account_id = "treasury.near"
    public_key = PublicKey.parse("ed25519:...")

    def sign(self, message: bytes) -> bytes:
        return kms.sign(key_id=..., message=message)

client = Near(network="mainnet", signer=KmsSigner())

What's under the hood

Borsh serialization via pyborsh (Pydantic-native, byte-verified against Rust), ed25519/ML-DSA via pyca/cryptography, HTTP via httpx. Every transaction byte this library produces is verified end-to-end against a real nearcore node in CI.

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

near_kit-1.2.0.tar.gz (301.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

near_kit-1.2.0-py3-none-any.whl (45.6 kB view details)

Uploaded Python 3

File details

Details for the file near_kit-1.2.0.tar.gz.

File metadata

  • Download URL: near_kit-1.2.0.tar.gz
  • Upload date:
  • Size: 301.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.14

File hashes

Hashes for near_kit-1.2.0.tar.gz
Algorithm Hash digest
SHA256 8b82e81c92dfde4dcd051eac4315873e7fcdcf16667fb60ca293a9f8a7cb2efa
MD5 0f7ab0589d2b308e24539ddbcfae9b70
BLAKE2b-256 c792e986b84c49ab3476693d4f9af1a5276f0aa0d469af0b834b3b19f5fee341

See more details on using hashes here.

Provenance

The following attestation bundles were made for near_kit-1.2.0.tar.gz:

Publisher: release.yml on r-near/near-kit-py

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file near_kit-1.2.0-py3-none-any.whl.

File metadata

  • Download URL: near_kit-1.2.0-py3-none-any.whl
  • Upload date:
  • Size: 45.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.14

File hashes

Hashes for near_kit-1.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 8bce4d09e31686344aeffc530f88535b01768c0e771ca30879650bf98c6aa33c
MD5 e429de666f628815285b20278fa6d93f
BLAKE2b-256 97bb91380bee72796c714ad6350e68c65702907edcd9627d4fa649ba027fbb93

See more details on using hashes here.

Provenance

The following attestation bundles were made for near_kit-1.2.0-py3-none-any.whl:

Publisher: release.yml on r-near/near-kit-py

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page