Skip to content

Web3 SDK Reference

Last updated: 2026-06-28

Use Web3 integration when you need direct contract reads or writes. Most application traffic uses the hosted gateway or a router API; Web3 is for protocol-level tooling, dashboards, operators, wallets, and integrations that manage sessions or inspect task state directly.

Contract Flow

flowchart TB
  App["Web3 app / operator tool"] --> Session["SessionV2"]
  Session --> Data["SessionData"]
  Session --> Queue["SessionQueueV2"]
  Queue --> QueueData["SessionQueueData"]
  Queue --> Validation["SessionQueueValidation"]
  Session --> NodePool["NodePool / NodePoolData"]
  Session --> Payment["SessionPayment / staking payment"]
  Queue --> Results["Task results"]

Install

npm install ethers

Configure

Keep RPC URLs, private keys, ABIs, and deployment addresses outside frontend code.

export CORTENSOR_RPC_URL=""
export CORTENSOR_PRIVATE_KEY=""
export CORTENSOR_SESSION_V2_ADDRESS=""
export CORTENSOR_SESSION_QUEUE_V2_ADDRESS=""

Set these variables from the active network matrix and never ship private keys in frontend bundles.

import { ethers } from "ethers";
import sessionV2Abi from "./abi/SessionV2.json" assert { type: "json" };
import sessionQueueV2Abi from "./abi/SessionQueueV2.json" assert { type: "json" };

const provider = new ethers.JsonRpcProvider(process.env.CORTENSOR_RPC_URL);
const signer = new ethers.Wallet(process.env.CORTENSOR_PRIVATE_KEY, provider);

const session = new ethers.Contract(
  process.env.CORTENSOR_SESSION_V2_ADDRESS,
  sessionV2Abi,
  signer
);

const sessionQueue = new ethers.Contract(
  process.env.CORTENSOR_SESSION_QUEUE_V2_ADDRESS,
  sessionQueueV2Abi,
  signer
);

const network = await provider.getNetwork();
console.log({ chainId: Number(network.chainId) });

Address Table

Use the address table for the active network. At minimum, session integrations normally need:

Module Purpose
ACL / IAM Access control and identity/role permissions.
RuntimeV1 / NetworkData Runtime and network configuration reads.
SessionV2 Creates, updates, deactivates, and submits work to sessions.
SessionData Stores session records used by SessionV2.
SessionQueueV2 Queues tasks and exposes task/result reads.
SessionQueueData Stores task and task-result state.
NodePool / NodePoolData / NodeSpec Selects nodes and exposes node capacity/model metadata.
SessionPayment / SessionPaymentData / staking payment modules Handles per-session payment flows when enabled.
PrivacySettingData Stores session/task privacy and allowlist settings where enabled.
ValidatorStats / QuantitiveStats / QualitativeStats / QualityStatsData Validator and quality-stat state.

Create A Session

The SessionV2.create ABI includes stakeToUse as the final argument.

function create(
  string memory name,
  string memory metadata,
  address variableAddress,
  uint256 minNumOfNodes,
  uint256 maxNumOfNodes,
  uint256 redundant,
  uint256 numOfValidatorNodes,
  uint256 mode,
  bool reserveEphemeralNodes,
  uint256 sla,
  uint256 modelIdentifier,
  uint256 reservePeriod,
  uint256 maxTaskExecutionCount,
  bool stakeToUse
) external;

Session mode values:

Mode Meaning
0 Ephemeral node selection.
1 Hybrid session.
2 Dedicated session.

Example:

const owner = await signer.getAddress();

const tx = await session.create(
  "API completion session",
  JSON.stringify({ purpose: "completion", environment: "testnet" }),
  owner,
  1,      // minNumOfNodes
  3,      // maxNumOfNodes
  1,      // redundant
  0,      // numOfValidatorNodes
  0,      // mode: ephemeral
  false,  // reserveEphemeralNodes
  0,      // sla
  0,      // modelIdentifier
  300,    // reservePeriod
  5,      // maxTaskExecutionCount
  false   // stakeToUse
);

const receipt = await tx.wait();
console.log(receipt.hash);

Read session events from the receipt or listen for SessionCreated(uint256 sessionId, bytes32 sid, address owner, address[] miners).

Read Sessions

const sessionId = 0n;
const sessionRecord = await session.getSession(sessionId);
console.log(sessionRecord);

For owner-level session lists, use the active ABI for the deployed SessionV2 contract. Some deployments expose paginated reads such as getSessionsByAddressByPage(address,uint256,uint256) rather than an unpaginated helper.

Submit A Task

The SessionV2.submit ABI includes requestParams before clientReference.

function submit(
  uint256 sessionId,
  uint256 nodeType,
  string calldata taskData,
  uint256 promptType,
  string calldata promptTemplate,
  uint256[] calldata llmParams,
  uint256[] calldata requestParams,
  string calldata clientReference
) public;

nodeType must match the session mode. For a simple prompt, set promptType to the mode expected by the deployment and keep promptTemplate empty unless the session requires a template.

const taskData = JSON.stringify({
  prompt: "Explain Cortensor in one paragraph.",
  stream: false
});

const llmParams = [
  160, // maxTokens
  7,   // temperature scale used by deployment adapter, if applicable
  10,  // topP scale used by deployment adapter, if applicable
  0,   // topK
  0,   // presencePenalty
  0    // frequencyPenalty
];

const requestParams = [
  120, // param0: execution/precommit timeout
  180, // param1: overall timeout or deployment-specific request setting
  0,
  0,
  0,
  0
];

const tx = await session.submit(
  0,                 // sessionId
  0,                 // nodeType
  taskData,
  1,                 // promptType
  "",
  llmParams,
  requestParams,
  "web3-demo-001"
);

await tx.wait();

The contract emits TaskSubmitted(uint256 sessionId, uint256 taskId, string taskData, string clientReference).

Read Tasks And Results

const tasks = await sessionQueue.getTasksBySessionId(0);
console.log(tasks);

const [miners, results] = await sessionQueue.getTaskResults(0, 0);
console.log({ miners, results });

const [resultMiners, resultValues, resultHashes] =
  await sessionQueue.getTaskResultsAndHashes(0, 0);
console.log({ resultMiners, resultValues, resultHashes });

Task results may be direct strings or off-chain URNs, depending on the route/session configuration.

Useful Events

Contract Event
SessionV2 SessionCreated(uint256 sessionId, bytes32 sid, address owner, address[] miners)
SessionV2 TaskSubmitted(uint256 sessionId, uint256 taskId, string taskData, string clientReference)
SessionV2 SessionUpdated(uint256 indexed sessionId, address indexed updater, uint256 minNumOfNodes, uint256 maxNumOfNodes, uint256 redundant)
SessionV2 SessionDeactivated(uint256 indexed sessionId, address indexed deactivator)
SessionQueueV2 TaskQueued(uint256 sessionId, uint256 taskId, uint256 globalId, string taskData)
SessionQueueV2 TaskAssigned(uint256 sessionId, uint256 taskId, address[] miners)
SessionQueueV2 TaskAcked, TaskPrecommitted, TaskCommitted, TaskEnded lifecycle events
sessionQueue.on("TaskEnded", (sessionId, taskId, miners, event) => {
  console.log({
    sessionId: sessionId.toString(),
    taskId: taskId.toString(),
    miners,
    tx: event.log.transactionHash
  });
});

Read Before Write

Before sending transactions:

  1. Confirm the RPC URL and chain ID.
  2. Confirm the contract address table belongs to that network.
  3. Confirm the ABI matches the deployed contract.
  4. Read the relevant state first.
  5. Estimate gas.
  6. Send the transaction.
  7. Wait for confirmation and record the transaction hash.
const gas = await session.submit.estimateGas(
  0,
  0,
  taskData,
  1,
  "",
  llmParams,
  requestParams,
  "web3-demo-001"
);

console.log({ gas: gas.toString() });

Security Notes

  • Never embed private keys in frontend code.
  • Use read-only providers for public dashboards.
  • Keep write operations server-side, in wallets, or in controlled operator tooling.
  • Validate chain ID before signing.
  • Store the ABI and address table with the deployment version they belong to.
  • Treat off-chain URNs as references; fetch and verify content according to the active privacy and storage policy.