> ## Documentation Index
> Fetch the complete documentation index at: https://docs.gol.network/llms.txt
> Use this file to discover all available pages before exploring further.

# DeFi agent with Privy and AgentKit

> A working Base Sepolia example of owner-controlled USDC transfers with a Privy wallet, Coinbase AgentKit, and GOL mandates.

The [mandate demo](https://github.com/Gol-Network/mandate-demo) connects a Privy embedded wallet to an OpenAI agent built with Coinbase AgentKit. The owner approves recipients, transfer limits, a total budget, expiry, and gas reimbursement limits in their wallet. The agent can then request USDC transfers from that same account. GOL checks each request against the owner's on-chain mandate.

<CardGroup cols={2}>
  <Card title="Open the demo" icon="arrow-up-right-from-square" href="https://gol-mandate-demo.vercel.app">
    Explore the deployed Base Sepolia application.
  </Card>

  <Card title="Browse the source" icon="github" href="https://github.com/Gol-Network/mandate-demo">
    Read the Next.js application, its GOL integration, and its tests.
  </Card>
</CardGroup>

This example uses the **Base Sepolia testnet**, the GOL version 3 core, hosted API **0.5.0**, and `@gol/sdk@0.5.0`. The application is a demonstration, not an audited or mainnet product. The [availability page](/availability) defines the exact supported account configurations and limits.

## How it works

```mermaid theme={null}
sequenceDiagram
  participant Owner as Owner in Privy
  participant App as Demo application
  participant Agent as OpenAI and AgentKit
  participant GOL as GOL API and relayer
  participant Chain as Base Sepolia
  Owner->>App: Sign in with embedded EOA
  App->>GOL: Prepare EIP-7702 setup
  Owner->>App: Sign delegation and initialization
  App->>GOL: Submit sponsored setup
  GOL->>Chain: Delegate EOA to reviewed Nexus and install core
  App->>GOL: Prepare transfer and gas policy
  Owner->>Chain: Sign and send approval
  Owner->>Agent: Ask to pay a named recipient
  Agent->>App: Call transfer_usdc
  App->>GOL: Prepare, sign, and submit action
  GOL->>Chain: Execute within mandate and settle gas inline
  App->>Chain: Read receipt for independent proof
```

The account remains the owner's EOA. GOL's reviewed EIP-7702 setup delegates it to Biconomy Nexus 1.3.3 and installs the GOL core. Privy holds the owner key and presents the owner's signing requests. The demo server holds a separate, unfunded agent signer and a scoped GOL test API key. GOL's relayer submits agent actions and receives network gas reimbursement in the same transaction, within the owner's signed caps. The agent signer never pays gas or receives the owner's funds.

| Part                         | Responsibility in this example                                                                                            |
| ---------------------------- | ------------------------------------------------------------------------------------------------------------------------- |
| Privy                        | Authenticate the owner, provide the embedded EOA, and sign owner approvals and EIP-7702 authorization.                    |
| Next.js server               | Verify the Privy session and linked account, keep the GOL API key and agent key server-side, and call the public GOL API. |
| OpenAI and Coinbase AgentKit | Interpret a request and invoke the demo's `transfer_usdc` tool. AgentKit's built-in transfer tools are not registered.    |
| GOL SDK and API              | Prepare and verify owner payloads, prepare agent actions, relay transactions, and report execution state.                 |
| GOL core on Base Sepolia     | Enforce the mandate and gas policy on every agent action, independently of the model or demo server.                      |

## Code highlights

These excerpts point to the [complete source](https://github.com/Gol-Network/mandate-demo). They show integration boundaries; the repository contains the surrounding authentication, error handling, polling, and UI code.

### Bind the owner's wallet before signing

Privy can have more than one linked wallet. The demo binds its EIP-7702 signer to the EOA being set up, and the SDK verifies that the authorization and initialization signatures recover to that account. A signature from another linked wallet is refused before submission.

```ts theme={null}
// lib/privy-signers.ts
export function boundPrivyAuthorization(signAuthorization, account) {
  return (input) => signAuthorization(input, { address: account });
}

// app/page.tsx
const body = await signPreparedEip7702Setup(
  { authorization: ownerAuthorizationSigner, initialization: ownerRawHashSigner },
  prepared,
  { account },
);
```

See the [Privy signer adapter](https://github.com/Gol-Network/mandate-demo/blob/main/lib/privy-signers.ts) and [owner flow](https://github.com/Gol-Network/mandate-demo/blob/main/app/page.tsx). The second call above is abbreviated; the application builds those signer adapters from the active Privy wallet.

### Turn the owner's choices into a mandate

The owner enters 1 to 16 payees, a maximum per transfer, a lifetime total, and gas limits. Only payee addresses become authority. Names remain local labels for the agent interface. The server prepares a policy, and the browser asks the owner to sign only after the SDK checks the prepared payload against the form values.

```ts theme={null}
// app/page.tsx, abbreviated
const prepared = await golPost("/api/gol/prepare-policy", formToRequest(values, account, agent));
const call = await signPreparedGasPolicy(ownerSigner, prepared, {
  agent,
  recipients: values.contacts.map((contact) => contact.address),
  maxPerActionBaseUnits: BigInt(values.maxPerActionBaseUnits),
  maxTotalBaseUnits: BigInt(values.maxTotalBaseUnits),
  maxGasPerActionWei: BigInt(values.maxPerActionWei),
  maxGasTotalWei: BigInt(values.maxTotalWei),
  chargeableOutcomesMask: values.chargeableOutcomesMask,
  relayer: { mode: "gol" },
});
```

The owner sends the approval transaction and pays its network gas. The agent cannot create or widen that approval with the GOL API key. See [policy preparation](https://github.com/Gol-Network/mandate-demo/blob/main/app/api/gol/prepare-policy/route.ts), [owner signing](https://github.com/Gol-Network/mandate-demo/blob/main/app/page.tsx), and [the hosted gas guide](/guides/hosted-gas).

### Give AgentKit one payment path

The demo registers one custom GOL action provider. The model chooses a payee name and an amount; code resolves the name to an address, parses the amount in USDC base units, and asks GOL to prepare the action. The agent signs the prepared action and its maximum network charge before submission.

```ts theme={null}
// lib/server/gol-action-provider.ts, abbreviated
const payee = resolveForAgent(binding.contacts, to);
if (!isResolved(payee)) return JSON.stringify({ ok: false, message: payee.message });

const actionId = newActionId();
const prepared = await gol.prepareGasExecution(projectId, actionId, {
  mandateId: binding.mandateId,
  gasPolicyId: binding.gasPolicyId,
  recipient: payee.address,
  amountBaseUnits: amount.toString(),
  deadline,
});
const signed = await signPreparedGasExecution(agentSigner, prepared, {
  maxChargeWei: serverEnv.agentMaxChargeWei,
});
const execution = await gol.submitGasExecution(projectId, actionId, signed);
```

`actionId` is the idempotency key. If a submission times out, the demo looks up that ID before reporting its outcome, because the transaction may already have been sent. An unknown payee name is stopped by name resolution. A valid address outside the owner's allowlist can reach the core, which refuses it on-chain. See the [action provider](https://github.com/Gol-Network/mandate-demo/blob/main/lib/server/gol-action-provider.ts) and [AgentKit registration](https://github.com/Gol-Network/mandate-demo/blob/main/app/api/agent/chat/route.ts).

### Show API state beside chain evidence

The [proof panel](https://github.com/Gol-Network/mandate-demo/blob/main/components/proof-panel.tsx) fetches GOL's execution details and independently reads the transaction receipt from public Base Sepolia RPC. It decodes the core's execution or refusal event, USDC `Transfer`, and inline `GasSettled` event. It displays the two views together and flags a disagreement. A receipt can appear before GOL confirms the action at Base's `safe` head; `safe` is not Ethereum finality.

The example's live test verified one owner approval and one 0.1 USDC agent transfer with on-chain `MandateActionExecuted`, USDC `Transfer`, and `GasSettled` events. The demo's owner-specific on-chain refusal and delegation-reset paths have not been verified live. The [receipt decoder tests](https://github.com/Gol-Network/mandate-demo/blob/main/test/proof-live-fixture.test.ts) cover a recorded transfer and a refusal fixture.

The Vercel site and its unauthenticated API guards have been checked. An authenticated run at the hosted origin is pending confirmation of that domain in the Privy app settings.

## Use the pattern with another stack

GOL's authority is the owner-signed policy and the compatible account's on-chain enforcement. Privy, Next.js, AgentKit, and OpenAI are application choices in this example. A different stack can use the same public API and SDK if it supplies the required signing and account behavior.

| Replace                                       | Keep the GOL integration contract                                                                                                                                                                            |
| --------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| Privy with another wallet provider            | The owner wallet must sign the exact payload for an [actively supported account configuration](/guides/accounts). EIP-7702 setup also needs the owner authorization and raw-hash signature the SDK verifies. |
| AgentKit or OpenAI with another agent runtime | Give the runtime a tool that calls `prepareGasExecution`, signs the prepared action with the mandate's agent signer, and calls `submitGasExecution`. The model does not enforce the mandate.                 |
| Next.js with another server framework         | Keep the project API key and agent signer on the server, authenticate each user, and call `@gol/sdk/server` or the public HTTP API.                                                                          |
| The demo's polling UI with another interface  | Read execution state through the API or [signed webhooks](/guides/webhooks), and use the transaction receipt when you need independent chain evidence.                                                       |

Account support is specific to reviewed implementations and configurations; a wallet provider alone does not make an account compatible. [Integrate hosted gas](/guides/hosted-gas) covers the complete supported flow beyond this application example.

## Run the example

Clone the [repository](https://github.com/Gol-Network/mandate-demo), use Node.js 22 or later and pnpm 11, and follow its [setup guide](https://github.com/Gol-Network/mandate-demo#setup). You need a Privy app with an embedded EOA, a GOL test project with a scoped key, an OpenAI API key, and an agent signing key. The owner needs Base Sepolia ETH for the approval and inline gas reimbursement, plus testnet USDC for transfers. Keep the GOL and OpenAI keys and the agent key server-side; the owner key stays in their wallet.

```sh theme={null}
pnpm install
cp .env.example .env.local
pnpm key:agent
pnpm check:env --write
pnpm dev
```

The demo asks the owner to configure payees and limits, approve the mandate, and then visit `/agent`. Owner pause, resume, and revocation are separate wallet actions and require no cooperation from the agent.
