Local quickstart
Build the SDK from this checkout and connect a local agent without using mainnet funds.
Prerequisites
- Run commands from the SOVRx402 repository root with Node.js, npm, and the repository dependencies already available. These instructions do not assume a published SDK package.
- Use an isolated local Anvil node and local test wallets. npm run node:robinhood uses the Anvil executable path recorded in package.json; that executable must exist on your machine.
- Source wallet keys and any gateway/facilitator Bearer tokens from your own local configuration. Never put mainnet keys, real API tokens, or private environment files in website code.
- Before a paid example, provision the agent with local ETH for gas and enough locally minted MockUSDC for the configured deposit and calls. MockUSDC exposes mint(address,uint256) for local provisioning; SDK registration does not mint tokens or top up gas.
Prepare local configuration
For a first setup, create .env.robinhood.local from the local example without replacing an existing file. Fill PRIVATE_KEY, FACILITATOR_PRIVATE_KEY, SMOKE_FUNDING_PRIVATE_KEY, and SMOKE_AGENT_PRIVATE_KEY with distinct local test wallets. Set treasury and operator addresses to the intended local roles; OPERATOR_ADDRESS must match the gateway PRIVATE_KEY.
Keep CHAIN_PROFILE=robinhoodLocal, CHAIN_ID=4663, loopback RPC_URL and GATEWAY_URL, and the local EIP-3009 mock-token configuration. Use the gateway's exact PRICE_PER_CALL in token base units. If Bearer protection is enabled locally, use separate GATEWAY_API_TOKEN and FACILITATOR_API_TOKEN values; the SDK receives only the gateway token.
# First setup only; keep any existing local configuration.
cp -n .env.robinhood.local.example .env.robinhood.local
chmod 600 .env.robinhood.local
# Build from the repository, after dependencies are available.
npm run compile
npm --prefix packages/sdk run buildStart the local services
Use separate terminals for the long-running node, facilitator, and gateway. Start a node only when its port is free; reuse an existing verified local deployment when appropriate. The first deployment writes token and proxy addresses back to .env.robinhood.local. Start the services after deployment and verification finish.
# Terminal 1: local node, only when 8545 is unused.
npm run node:robinhood
# Terminal 2: first local deployment only, then verify.
ENV_FILE=.env.robinhood.local npm run deploy:local
ENV_FILE=.env.robinhood.local npm run verify:local
# Terminal 3: leave running.
ENV_FILE=.env.robinhood.local npm run facilitator:local
# Terminal 4: leave running.
ENV_FILE=.env.robinhood.local npm run gateway:localConnect the built SDK
This Node example reads only .env.robinhood.local and performs setup and status reads. Place it at the repository root. It requires local services and deployed contract addresses; it does not run inside the website.
usdcAddress remains required by BaseAgentConfig even when tokenAddress is supplied. Pass the same configured payment-token address to both fields. All amounts are integer base units, not decimal token strings.
const { readFileSync } = require("node:fs");
const { parse } = require("dotenv");
const { JsonRpcProvider } = require("ethers");
const { BaseAgent } = require("./packages/sdk/dist/packages/sdk/index.js");
const env = parse(readFileSync(".env.robinhood.local"));
function required(name) {
if (!env[name]) throw new Error("Missing local setting: " + name);
return env[name];
}
async function main() {
const rpcUrl = required("RPC_URL");
const gatewayUrl = required("GATEWAY_URL");
const local = [rpcUrl, gatewayUrl].every(raw => {
const url = new URL(raw);
return url.protocol === "http:" && url.hostname === "127.0.0.1"
&& !url.username && !url.password;
});
if (env.CHAIN_PROFILE !== "robinhoodLocal" || !local) {
throw new Error("This example requires local Anvil and gateway URLs");
}
const rpc = new JsonRpcProvider(rpcUrl);
try {
const client = await rpc.send("web3_clientVersion", []);
if (!/anvil|hardhatnetwork/i.test(client)) throw new Error("Local node required");
} finally {
rpc.destroy();
}
const tokenAddress = required("PAY_TOKEN_ADDRESS");
const agent = new BaseAgent({
privateKey: required("SMOKE_AGENT_PRIVATE_KEY"),
rpcUrl,
gatewayUrl,
gatewayApiToken: env.GATEWAY_API_TOKEN || undefined,
chainId: 4663,
registryAddress: required("REGISTRY_ADDRESS"),
ledgerAddress: required("LEDGER_ADDRESS"),
usdcAddress: tokenAddress,
tokenAddress,
pricePerCall: BigInt(required("PRICE_PER_CALL")),
});
await agent.setup();
console.log(await agent.getStatus());
}
main().catch(error => {
console.error(error.message);
process.exitCode = 1;
});Make one local prepaid call
This optional fragment belongs inside main() after setup, using the same verified local agent. It sends local registration/approval transactions and authorizes one local token payment. The website displays this example as text and never executes it.
Use a funded local test wallet and a writable local gateway running the resource API. Persist the requestId before invoking a business request. A failed or pending response must be reconciled with that ID; rerunning the fragment creates a new payable request.
await agent.register();
const { randomBytes } = require("node:crypto");
const requestId = "0x" + randomBytes(32).toString("hex");
console.log({ requestId });
const result = await agent.call("/resources/address-snapshot?view=all", {
requestId,
mode: "prepaid",
});
console.log(result.data);
console.log(await agent.getResult(requestId));