---
name: obento
description: Put idle USDC on Base to work in Obento's vault, and withdraw it. Use when an agent holds USDC on Base that it will not need for a while and wants it earning, or needs to check or take back what it deposited.
---

# Earn on USDC with Obento

Obento's vault lends USDC across vetted lending markets on Base, and Autopilot moves it when rates change. A deposit returns obUSD, the vault's share. Its price rises as the vault earns, after a 10% fee on new lending profit. You can withdraw at any time.

## Before you send

1. `GET https://obentoapp.com/api/vault`. Stop if `paused` is `true` or `priceFresh` is `false`. Read:
   - `price`: USDC per obUSD, with 6 decimals. `1000000` is $1.00.
   - `apy`: the yearly rate after the fee, as a fraction. `0.0431` is 4.31%.
   - `ready`: the USDC that can be withdrawn at once, in dollars.
2. Use Base mainnet, chain ID `8453`. You pay your own gas in ETH: each transaction below uses about 200,000 gas.

## Addresses

| Contract | Address |
| --- | --- |
| USDC | `0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913` |
| Vault (obUSD) | `0xB24366D770477C8192eC98851137A1eF8530A1e5` |
| Gateway | `0x3BFAC87918c69D02e4288bDcC503AF7F545d735C` |

## Deposit

1. On USDC: `approve(gateway, assets)`
2. On the gateway: `deposit(vault, assets, minSharesOut, receiver, 2)`

`assets` is USDC with 6 decimals. Set `minSharesOut` to `assets × 1,000,000 ÷ price`, less 0.5%. `receiver` gets the obUSD, and `2` is the partner ID for agents. Autopilot lends new money on its next pass, every 15 minutes.

## Withdraw

1. On the vault: `balanceOf(you)` gives your obUSD; withdraw all of it or part.
2. On the vault: `approve(gateway, shares)`
3. On the gateway: `redeem(vault, shares, minAssetsOut, receiver, 2)`

Set `minAssetsOut` to `shares × price ÷ 1,000,000`, less 0.5%. When the vault's ready cash covers the withdrawal, the USDC arrives in the same transaction and `redeem` returns the amount. Otherwise `redeem` returns `0`: the withdrawal joins a queue at the price of the request, and Autopilot pays it on its next pass, usually within 15 minutes.

## Example with viem

```ts
import { createPublicClient, createWalletClient, http, parseAbi, parseUnits } from 'viem';
import { privateKeyToAccount } from 'viem/accounts';
import { base } from 'viem/chains';

const USDC = '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913';
const VAULT = '0xB24366D770477C8192eC98851137A1eF8530A1e5';
const GATEWAY = '0x3BFAC87918c69D02e4288bDcC503AF7F545d735C';
const AGENTS = 2;
const erc20 = parseAbi([
  'function approve(address spender, uint256 amount) returns (bool)',
  'function balanceOf(address owner) view returns (uint256)',
]);
const gateway = parseAbi([
  'function deposit(address yoVault, uint256 assets, uint256 minSharesOut, address receiver, uint32 partnerId) returns (uint256)',
  'function redeem(address yoVault, uint256 shares, uint256 minAssetsOut, address receiver, uint32 partnerId) returns (uint256)',
]);

const account = privateKeyToAccount(process.env.AGENT_KEY as `0x${string}`);
const wallet = createWalletClient({ account, chain: base, transport: http() });
const chain = createPublicClient({ chain: base, transport: http() });
const send = async (hash: Promise<`0x${string}`>) => chain.waitForTransactionReceipt({ hash: await hash });

const vault = await (await fetch('https://obentoapp.com/api/vault')).json();
if (vault.paused || !vault.priceFresh) throw new Error('Obento is not taking deposits right now');
const price = BigInt(vault.price);

// Put $100 to work.
const assets = parseUnits('100', 6);
const minShares = ((assets * 1_000_000n) / price) * 995n / 1000n;
await send(wallet.writeContract({ address: USDC, abi: erc20, functionName: 'approve', args: [GATEWAY, assets] }));
await send(wallet.writeContract({ address: GATEWAY, abi: gateway, functionName: 'deposit', args: [VAULT, assets, minShares, account.address, AGENTS] }));

// Take it all back.
const shares = await chain.readContract({ address: VAULT, abi: erc20, functionName: 'balanceOf', args: [account.address] });
const minAssets = ((shares * price) / 1_000_000n) * 995n / 1000n;
await send(wallet.writeContract({ address: VAULT, abi: erc20, functionName: 'approve', args: [GATEWAY, shares] }));
await send(wallet.writeContract({ address: GATEWAY, abi: gateway, functionName: 'redeem', args: [VAULT, shares, minAssets, account.address, AGENTS] }));
```

## Check your position

`GET https://obentoapp.com/api/earnings?address=0x…` returns what you put in, took out, hold now and earned, Autopilot's fee in dollars, and every deposit and withdrawal with its status: `paid`, `queued` or `returned`.

## Know before you deposit

- One fee: 10% of new lending profit, taken before the price is published. Deposits and withdrawals are free.
- The vault and the markets it lends to can fail, and USDC can lose its peg. Obento's own contracts have not had an independent audit. Read [the risks](https://obentoapp.com/docs/risks.md).
- Amounts under $1 stay as ready cash until the vault holds enough to lend.
