@awarizon/web3
Core SDK. Works in Node 18+, Deno, Bun, Edge runtimes, and any browser bundler. Zero framework dependencies.
new AwarizonWeb3(config)
Creates an SDK instance. All .contract() calls share the same connection pool.
import { AwarizonWeb3 } from "@awarizon/web3" const awarizon = new AwarizonWeb3({ chain: "base", // required — target EVM chain apiKey: "awz_live_...", // required — from your dashboard timeout: 30_000, // optional, ms (default: 30 000) retries: 3, // optional (default: 3) })
chainSupportedChainREQEVM chain identifier string. See Supported Chains.apiKeystringREQAPI key from the dashboard. Format: "awz_live_..."timeoutnumberRequest timeout in milliseconds. Default 30 000.retriesnumberAutomatic retries on transient RPC errors. Default 3.rpcUrlstringCustom RPC endpoint override.signerWalletClientPre-connected viem WalletClient — equivalent to calling connectWallet() after construction.awz.contract(options) → ContractInstance
Binds the SDK to a deployed contract. Returns a fully-typed ContractInstance where every ABI function is a direct method call.
const token = await awarizon.contract({ address: "0xContractAddress", // EIP-55 checksum address abi: ABI_ARRAY, // standard JSON ABI }) // Every ABI function becomes a direct method — reads and writes const symbol = await token.symbol() // string const balance = await token.balanceOf(ownerAddress) // bigint const tx = await token.transfer(to, amount) // TransactionResult
ERC Standard Clients
Load ERC-20, ERC-721, and ERC-1155 contracts with zero ABI imports. Every method is fully typed — your editor autocompletes the entire standard interface.
// ── ERC-20 Token ────────────────────────────────────────────────────────────── const usdc = await awarizon.erc20("0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48") const name = await usdc.name() // "USD Coin" const symbol = await usdc.symbol() // "USDC" const decimals = await usdc.decimals() // 6 const supply = await usdc.totalSupply() // bigint const balance = await usdc.balanceOf(owner) // bigint const allowed = await usdc.allowance(owner, spender) await usdc.transfer(recipient, 1_000_000n) // 1 USDC await usdc.approve(spender, 500_000n) await usdc.transferFrom(from, to, 1_000_000n) // ── ERC-721 NFT Collection ──────────────────────────────────────────────────── const nft = await awarizon.erc721("0xBC4CA0EdA7647A8aB7C2061c2E118A18a936f13D") const owner = await nft.ownerOf(1n) // `0x${string}` const uri = await nft.tokenURI(1n) // "ipfs://..." const count = await nft.balanceOf(wallet) // bigint await nft.safeTransferFrom(from, to, 1n) await nft.approve(operator, 1n) await nft.setApprovalForAll(operator, true) // ── ERC-1155 Multi-Token ────────────────────────────────────────────────────── const items = await awarizon.erc1155("0x...") const qty = await items.balanceOf(user, 42n) const uri = await items.uri(42n) const batched = await items.balanceOfBatch([u1, u2], [1n, 2n]) await items.safeTransferFrom(from, to, 42n, 1n, "0x") await items.setApprovalForAll(operator, true)
Contract Registry
Register contracts once by name at startup. Reference them anywhere in your app without repeating addresses or ABIs.
// Register at startup — returns `this` for chaining awarizon .register("USDC", { address: "0x...", abi: erc20Abi }) .register("Vault", { address: "0x...", abi: vaultAbi }) .register("NFT", { address: "0x...", abi: erc721Abi }) // Use by name anywhere — address and ABI never repeated again const usdc = await awarizon.use("USDC") const vault = await awarizon.use("Vault") const nft = await awarizon.use("NFT") await usdc.transfer(recipient, 100_000n) await vault.deposit(1_000n) awarizon.registeredContracts() // ["USDC", "Vault", "NFT"] awarizon.unregister("Vault")
Reading state
Call any view or pure function directly. Zero gas, no wallet required.
// Single return value const balance = await contract.balanceOf(ownerAddress) // bigint const symbol = await contract.symbol() // string const decimals = await contract.decimals() // bigint // Tuple return — destructure directly const [reserve0, reserve1] = await contract.getReserves() // Struct — returned as Record<string, unknown> const position = await contract.positions(tokenId)
Writing transactions
nonpayable and payable functions return a TransactionResult immediately after broadcast. Call .wait() to block until confirmed.
// Broadcast and get hash immediately const tx = await contract.transfer(recipientAddress, 1_000_000n) console.log("broadcasted:", tx.hash) // 0x... // Wait for on-chain confirmation (1 block) const receipt = await tx.wait() console.log("block:", receipt.blockNumber) console.log("gas used:", receipt.gasUsed) console.log("status:", receipt.status) // "success" | "reverted" // Payable function — attach ETH via options object (last arg) const tx2 = await contract.deposit({ value: 1_000_000_000_000_000n }) // 0.001 ETH // Custom gas limit const tx3 = await contract.mint(quantity, { value: price, gas: 200_000n })
Events
Subscribe to real-time contract events. The SDK returns an unsubscribe function — always call it on cleanup.
// Subscribe to a named event const unsubscribe = contract.on("Transfer", (log) => { console.log("from:", log.args.from) console.log("to:", log.args.to) console.log("value:", log.args.value) }) // Unsubscribe (e.g. on component unmount) unsubscribe() // Wildcard — receive all events from this contract const unsubAll = contract.on("*", (log) => { console.log(log.name, log.args) })
Gas estimation
Simulate a write before broadcasting to get the estimated gas cost.
const gas = await contract.estimateGas( "transfer", // function name recipientAddress, // ...args 1_000_000n, ) console.log("estimated gas:", gas) // 21000n
Built-in Wallet
The SDK ships a full self-custodial wallet — generate new wallets, import from a 12 or 24-word BIP-39 mnemonic, or load from a raw private key. No browser extension or external library required.
// ── Create a brand-new wallet ───────────────────────────────────────────────── const created = await awarizon.wallet.create() console.log(created.address) // "0xAbCd..." console.log(created.privateKey) // "0x..." ← returned once — store it securely // ── Import from a BIP-39 mnemonic (12 or 24 words) ──────────────────────────── const fromPhrase = await awarizon.wallet.importMnemonic( "word1 word2 word3 word4 word5 word6 word7 word8 word9 word10 word11 word12", 0, // optional HD account index (default 0) ) // ── Import from a hex private key ───────────────────────────────────────────── const fromKey = await awarizon.wallet.importPrivateKey("0x...") // Once any wallet is loaded, all write calls use it automatically: const tx = await usdc.transfer(recipient, 1_000_000n)
wallet.address()AddressReturns the active wallet address. Throws WalletNotConnectedError if no wallet is loaded.wallet.isConnected()booleanTrue when any wallet — internal or external — is active.wallet.hasInternalWallet()booleanTrue when a locally generated or imported key/mnemonic wallet is loaded.wallet.hasExternalWallet()booleanTrue when an external WalletClient (wagmi, RainbowKit) has been injected.wallet.disconnect()voidClears all wallet state — both internal keys and external connections.getWalletInfo()WalletInfoReturns { address, chain, isExternal } — useful for displaying connected wallet state.Never store private keys or mnemonic phrases in plaintext, localStorage, or client-side variables. On mobile use expo-secure-store via @awarizon/react-native. On server, load from environment variables only.
External Wallets — wagmi & RainbowKit
Inject any viem-compatible WalletClient from wagmi or RainbowKit. A one-line sync component keeps the Awarizon SDK in lockstep with whatever wallet the user selects in wagmi — account switches and chain changes included.
wagmi — useWalletClient()
import { useEffect } from "react" import { useWalletClient } from "wagmi" import { useSDK } from "@awarizon/react" // Drop this inside any component that lives under both <WagmiProvider> and <AwarizonProvider> function WalletSync() { const awarizon = useSDK() const { data: walletClient } = useWalletClient() useEffect(() => { if (walletClient) awarizon.connectWallet(walletClient) else awarizon.disconnectWallet() }, [walletClient, awarizon]) return null // renders nothing — purely a sync effect }
RainbowKit — WalletSync + ConnectButton
import { useEffect } from "react" import { useWalletClient } from "wagmi" import { ConnectButton } from "@rainbow-me/rainbowkit" import { useSDK } from "@awarizon/react" // Syncs the active wagmi wallet into Awarizon whenever it changes function WalletSync() { const awarizon = useSDK() const { data: walletClient } = useWalletClient() useEffect(() => { if (walletClient) awarizon.connectWallet(walletClient) else awarizon.disconnectWallet() }, [walletClient, awarizon]) return null } // In your layout — WalletSync is invisible, ConnectButton handles the UI export default function Layout({ children }: { children: React.ReactNode }) { return ( <> <WalletSync /> {/* keeps Awarizon in sync with RainbowKit */} <ConnectButton /> {/* RainbowKit's button — shows connected address */} {children} </> ) }
EIP-1193 — Browser Wallet Direct Connect
Connect any injected browser wallet (MetaMask, Rabby, Brave, Coinbase, Phantom) directly via connectEIP1193Provider() — no wagmi, no extra dependencies.
// One call — requests accounts + subscribes to account/chain events await awarizon.connectEIP1193Provider(window.ethereum, { name: "MetaMask", // optional display name }) // All subsequent writes use this wallet const { hash } = await token.transfer("0x...", 100n) // Detect the injected wallet function detectWalletName(p: Record<string, unknown>): string { if (p.isMetaMask && !p.isRabby) return "MetaMask" if (p.isRabby) return "Rabby" if (p.isBraveWallet) return "Brave Wallet" if (p.isCoinbaseWallet) return "Coinbase Wallet" if (p.isPhantom) return "Phantom" return "Browser Wallet" }
If you use <ConnectButton /> from @awarizon/react, this is handled for you automatically — including wallet detection, WalletConnect QR, and the account popup.
WalletConnect — MetaMask · Trust · Rainbow · Coinbase
WalletConnect v2 is built into the SDK — no RainbowKit or wagmi required. Pass walletConnectProjectId at init to unlock direct connections to MetaMask Mobile, Trust Wallet, Rainbow, Coinbase Wallet, Uniswap, and any other WalletConnect-compatible app. Get a free project ID at cloud.walletconnect.com.
const awarizon = new AwarizonWeb3({ chain: "base", apiKey: "awz_live_...", walletConnectProjectId: "YOUR_WC_PROJECT_ID", // from cloud.walletconnect.com })
Calling connectWalletConnect() fires onDisplayUri with a wc:// URI string. On desktop, render it as a QR code. On mobile, turn it into a deep link that opens the user's wallet app directly.
Desktop — QR code (user scans from mobile wallet app)
import QRCode from "react-qr-code" // or any QR library import { useState } from "react" import { useSDK } from "@awarizon/react" function ConnectDesktop() { const awarizon = useSDK() const [uri, setUri] = useState<string | null>(null) async function connect() { await awarizon.connectWalletConnect({ onDisplayUri: (wcUri) => setUri(wcUri), }) setUri(null) // clear QR once connected } if (uri) return ( <div> <p>Scan with MetaMask, Trust, Rainbow, Coinbase, or any wallet app</p> <QRCode value={uri} size={240} /> </div> ) return <button onClick={connect}>Connect Wallet</button> }
Mobile — deep link buttons (opens the wallet app directly)
import { useState } from "react" import { useSDK } from "@awarizon/react" // WalletConnect v2 deep-link prefixes — each wallet registers its own URI scheme const WALLETS = [ { name: 'MetaMask', scheme: 'metamask://wc?uri=', icon: '🦊' }, { name: 'Trust Wallet', scheme: 'trust://wc?uri=', icon: '🛡️' }, { name: 'Rainbow', scheme: 'rainbow://wc?uri=', icon: '🌈' }, { name: 'Coinbase Wallet', scheme: 'cbwallet://wc?uri=', icon: '🔵' }, { name: 'Uniswap Wallet', scheme: 'uniswap://wc?uri=', icon: '🦄' }, ] function ConnectMobile() { const awarizon = useSDK() const [uri, setUri] = useState<string | null>(null) async function startConnect() { await awarizon.connectWalletConnect({ onDisplayUri: (wcUri) => setUri(wcUri), }) setUri(null) // clear once approved } if (uri) { return ( <div> <p>Choose your wallet:</p> {WALLETS.map(w => ( <a key={w.name} href={`${w.scheme}${encodeURIComponent(uri)}`} style={{ display: "block", margin: "8px 0" }} > {w.icon} Open in {w.name} </a> ))} </div> ) } return <button onClick={startConnect}>Connect Mobile Wallet</button> }
Detect navigator.userAgent at runtime to show QR (desktop) or deep-link buttons (mobile) automatically. <ConnectButton /> from @awarizon/react does this for you — it renders the correct UI for each platform without any extra setup.
MetaMask Mobilemetamask://wc?uri=...iOS · AndroidTrust Wallettrust://wc?uri=...iOS · AndroidRainbowrainbow://wc?uri=...iOS · AndroidCoinbase Walletcbwallet://wc?uri=...iOS · AndroidUniswap Walletuniswap://wc?uri=...iOS · AndroidAny WC v2 walletUniversal QR code fallbackAll platformsLive Wallet & Chain Tracking
When connected via connectEIP1193Provider() or connectWalletConnect(), the SDK subscribes to provider events automatically. No polling — the SDK state stays in sync with whatever the user does in their wallet app.
accountsChangedstring[]New account selected → rebuilds WalletClient, fires onWalletChange.accountsChanged[]Wallet locked / disconnected → calls disconnectExternal().chainChangedstringUser switched networks → fires onChainChange.disconnect—Provider disconnected → calls disconnectExternal().// Subscribe outside React if needed const unsub = awarizon.wallet.onWalletChange(({ address, type }) => { console.log("wallet:", address, type) // "external" | "internal" | "none" }) const unsub2 = awarizon.wallet.onChainChange(({ chainId }) => { console.log("chain:", chainId) }) unsub(); unsub2()
In React, useWallet() subscribes to both events automatically — address, chainId, and isChainMismatch update in real time without any setup.
Multicall — batch reads
Batch multiple view/pure reads into a single RPC round-trip via multicall3. Critical for dashboards that need many values at once — 10 reads becomes 1 request.
// 3 reads → 1 network request const [balance, symbol, decimals] = await awarizon.multicall([ { address: USDC, abi: erc20Abi, method: "balanceOf", args: [userAddress] }, { address: USDC, abi: erc20Abi, method: "symbol" }, { address: USDC, abi: erc20Abi, method: "decimals" }, ]) // Dashboard pattern — whole portfolio in one shot const [ethBal, usdcBal, daiSupply, nftOwner] = await awarizon.multicall([ { address: WETH, abi: erc20Abi, method: "balanceOf", args: [wallet] }, { address: USDC, abi: erc20Abi, method: "balanceOf", args: [wallet] }, { address: DAI, abi: erc20Abi, method: "totalSupply" }, { address: NFT, abi: erc721Abi, method: "ownerOf", args: [1n] }, ])