Skip to main content

What is the GAME SDK plugin?

The @mandate.md/game-plugin package adds Mandate policy enforcement to GAME SDK agents by Virtuals Protocol. It exposes GameWorker functions that validate every on-chain action against your Mandate spending policies before execution. Available in both TypeScript and Python.

Installation

bun add @mandate.md/game-plugin @virtuals-protocol/game
For TypeScript, @virtuals-protocol/game is a peer dependency (>=0.1.0).

Usage

import { createMandateWorker } from '@mandate.md/game-plugin';

const worker = createMandateWorker({
  runtimeKey: process.env.MANDATE_RUNTIME_KEY!,
  privateKey: process.env.PRIVATE_KEY! as `0x${string}`,
  chainId: 84532,
  rpcUrl: 'https://sepolia.base.org',
});

// Add to your GAME agent
const agent = new GameAgent({
  workers: [worker],
  // ... other configuration
});
The TypeScript version uses MandateWallet from the SDK for local signing. The Python version calls the Mandate API directly via HTTP for validation, and returns the result to the GAME agent for further action.

Functions

FunctionDescription
mandate_transferTransfer ERC20 tokens with policy enforcement. Args: to (or to_address), amount, token_address.
mandate_x402_payPay for an x402-gated resource. Args: url. TypeScript only.

Configuration

ParameterTypeRequiredDescription
runtimeKey / runtime_keystringYesMandate runtime key (mndt_live_... or mndt_test_...)
privateKey / private_keystringYes (TS only)Agent wallet private key (hex, 0x prefix)
chainId / chain_idnumber / intNoEVM chain ID. Defaults to 84532.
rpcUrl / rpc_urlstringNoRPC endpoint URL
workerDescriptionstringNoCustom description for the GameWorker (TS only)

Error handling

The GAME SDK uses a status-based return model. Functions return a FunctionResult with one of three statuses.
StatusMandate meaning
doneTransaction validated and sent. Result contains txHash and intentId.
failedBlocked by policy. Feedback contains the block reason (e.g., "Blocked by policy: daily_limit_exceeded").
pendingApproval required. Feedback contains the intentId for polling.
TypeScript example:
// The worker handles this internally. From the agent's perspective:
// { status: 'done', result: '{"txHash":"0x...","intentId":"int_abc123"}' }
// { status: 'failed', result: 'Blocked by policy: monthly_limit_exceeded' }
// { status: 'pending', result: 'Approval required. IntentId: int_abc123' }
The getEnvironment() method on the worker returns { chainId, policyEnforcement: 'active' }, giving the GAME agent context about its operating constraints.
The Python plugin uses urllib.request with no external HTTP dependencies. It validates the transaction with Mandate but does not sign or broadcast. Your GAME agent handles the actual on-chain execution after validation passes.

Next Steps

Integrations Overview

Compare all supported agent frameworks side by side.

SDK Overview

Use the TypeScript SDK directly for maximum control.

ACP Plugin

Add Mandate to ACP (Agent Commerce Protocol) for inter-agent payments.