Skip to Content
SDKFirst Onchain Script

First Onchain Script

This is the shortest end-to-end Beav3r onchain flow for the current model:

  1. Create a project and API key.
  2. Provision an onchain actor and get its account and trusted executor.
  3. Whitelist that executor at the destination contract.
  4. Submit an action and wait for approval.
  5. Mint authorization artifact.
  6. Execute onchain through the trusted executor.

Use:

  • staging: https://staging.server.beav3r.ai
  • production: https://server.beav3r.ai

Package setup

mkdir beav3r-onchain-quickstart && cd beav3r-onchain-quickstart npm init -y npm install @beav3r/sdk@beta viem

Before starting

Required:

  • Beav3r dashboard access: https://dashboard.beav3r.ai
  • one project API key with onchain scopes
  • one provisioned onchain actor (account + executor)
  • onchain signer registration configured in signer registry for that actor account and key id
  • one destination contract that whitelists the returned executor
  • funded wallet to submit the executeWithAuth(...) transaction on the target chain

Trusted executor model

Provisioning returns:

  • account: the actor identity bound into the authorization payload
  • executor: the contract address the destination should trust

The destination contract grants permissions to the executor address, such as an allowlist entry or role. At execution time, the destination sees msg.sender = executor.

Beav3r does not ask the destination to trust an EOA signer directly. The destination trusts the provisioned executor contract, and the executor only runs calls with a valid Beav3r authorization artifact.

If setup is incomplete, start with:

Script

Load these variables before running the example:

# Beav3r API configuration export BEAV3R_BASE_URL=https://staging.server.beav3r.ai export BEAV3R_API_KEY=project_api_key export BEAV3R_AGENT_ID=onchain_quickstart # Provisioned actor returned by Beav3r export ONCHAIN_ACTOR_ACCOUNT=0xactor_account export ONCHAIN_EXECUTOR_ADDRESS=0xtrusted_executor # Target chain and destination contract export ONCHAIN_CHAIN_ID=84532 export ONCHAIN_RPC_URL=https://base-sepolia-rpc.example export ONCHAIN_TOKEN_ADDRESS=0xtoken_contract # Funded EOA that submits executeWithAuth(...) onchain export ONCHAIN_EXECUTOR_CALLER_PRIVATE_KEY=0xyour_private_key
first-onchain-script.mjs
import { Beav3r, prepareOnchainExecution } from '@beav3r/sdk' import { createPublicClient, createWalletClient, encodeFunctionData, http, parseAbi } from 'viem' import { privateKeyToAccount } from 'viem/accounts' // 1. Load Beav3r API configuration. const baseUrl = process.env.BEAV3R_BASE_URL ?? 'https://staging.server.beav3r.ai' const apiKey = process.env.BEAV3R_API_KEY const agentId = process.env.BEAV3R_AGENT_ID ?? 'onchain_quickstart' if (!apiKey) { throw new Error('Missing BEAV3R_API_KEY') } // 2. Load the provisioned actor returned by Beav3r. const chainId = Number(process.env.ONCHAIN_CHAIN_ID ?? 84532) const account = process.env.ONCHAIN_ACTOR_ACCOUNT const executor = process.env.ONCHAIN_EXECUTOR_ADDRESS const token = process.env.ONCHAIN_TOKEN_ADDRESS if (!account || !executor || !token) { throw new Error('Missing ONCHAIN_ACTOR_ACCOUNT / ONCHAIN_EXECUTOR_ADDRESS / ONCHAIN_TOKEN_ADDRESS') } // 3. Load the RPC and funded EOA that will submit executeWithAuth(...). const rpcUrl = process.env.ONCHAIN_RPC_URL const pk = process.env.ONCHAIN_EXECUTOR_CALLER_PRIVATE_KEY if (!rpcUrl || !pk) { throw new Error('Missing ONCHAIN_RPC_URL / ONCHAIN_EXECUTOR_CALLER_PRIVATE_KEY') } const client = new Beav3r({ baseUrl, apiKey, agentId }) // 4. Prepare the destination call the trusted executor will make. const recipient = '0x1111111111111111111111111111111111111111' const amount = 25n * 10n ** 6n const transferData = encodeFunctionData({ abi: parseAbi(['function transfer(address to, uint256 amount) returns (bool)']), functionName: 'transfer', args: [recipient, amount] }) // 5. Submit the action to Beav3r and wait for approval. await client.guardAndWait( { actionType: 'payments.send_usdt', payload: { amount: '25', recipient, chainId, calldata: transferData } }, { pollIntervalMs: 2000, timeoutMs: 5 * 60 * 1000 } ) // 6. Ask Beav3r for an authorization artifact bound to this actor + executor. const now = Math.floor(Date.now() / 1000) const auth = await client.authorizeOnchainAction({ account, to: token, value: '0', data: transferData, chainId, nonce: BigInt(now), expiresAt: BigInt(now + 1200), executor }) // 7. Submit executeWithAuth(...) onchain through the trusted executor. const caller = privateKeyToAccount(pk) const publicClient = createPublicClient({ transport: http(rpcUrl) }) const walletClient = createWalletClient({ account: caller, transport: http(rpcUrl) }) const prepared = prepareOnchainExecution({ actor: { accountAddress: account, executorAddress: executor, chainId }, action: { to: token, value: '0', data: transferData, nonce: BigInt(now) }, artifact: auth.item.artifact }) const txHash = await walletClient.writeContract({ address: executor, abi: parseAbi([ 'function executeWithAuth(address to,uint256 value,bytes data,(bytes32 actionHash,address account,address executor,uint256 chainId,uint256 nonce,uint256 expiresAt,bytes32 keyId) auth,bytes signature) payable returns (bytes)' ]), functionName: 'executeWithAuth', args: [ prepared.to, prepared.value, prepared.data, prepared.auth, prepared.signature ] }) const receipt = await publicClient.waitForTransactionReceipt({ hash: txHash }) console.log({ txHash, status: receipt.status })

The TypeScript example uses prepareOnchainExecution(...) from @beav3r/sdk to:

  • verify the returned artifact matches the actor and request
  • normalize the auth payload fields
  • prepare the final executeWithAuth(...) call arguments

The Python example stays more explicit because the current helper lives in the JavaScript SDK.

Run it

BEAV3R_BASE_URL=https://staging.server.beav3r.ai \ BEAV3R_API_KEY=project_api_key \ ONCHAIN_RPC_URL=https://base-sepolia.infura.io/v3/<key> \ ONCHAIN_CHAIN_ID=84532 \ ONCHAIN_ACTOR_ACCOUNT=0x... \ ONCHAIN_EXECUTOR_ADDRESS=0x... \ ONCHAIN_TOKEN_ADDRESS=0x... \ ONCHAIN_EXECUTOR_CALLER_PRIVATE_KEY=0x... \ node first-onchain-script.mjs

Expected result

  • action reaches approval flow
  • authorization artifact is minted
  • executor call succeeds onchain
  • destination contract accepts execution because the trusted executor is caller

Continue with: