Skip to content

Commit 15cc34b

Browse files
youssefeaCodex
andcommitted
docs: add stock and DeFi use-case guides
Co-authored-by: Codex <codex-noreply@coinbase.com>
1 parent 9d40f8a commit 15cc34b

37 files changed

Lines changed: 1615 additions & 1131 deletions

docs/.mintignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
# Exclude specific files
22
writing.md
3-
3+
API_MIGRATION_PLAN.md
44

docs/AGENTS.md

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ description: Look up Base documentation with a compact directory-grouped index b
99
> High-signal index of section guides. Jump to a section's llms.txt for concise intros, curated links, and fast navigation.
1010
1111
- [Base Chain](./base-chain/llms.txt) — Start here for Base Chain docs, including concepts, network reference, node operation, APIs, and protocol specifications.
12-
- [Build On Base](./build-on-base/llms.txt) — Build on Base by outcome — issue stablecoins, facilitate payments, and run private transactions, with primitives built into the chain.
12+
- [Build On Base](./build-on-base/llms.txt) — Build financial products on Base by outcome — issue stablecoins, integrate DeFi, tokenize stocks, accept payments, or run private transactions.
1313
- [Fonts](./fonts/llms.txt)
1414
- [Get Started](./get-started/llms.txt)
1515
- [Sdks](./sdks/llms.txt) — Every SDK and API for building on Base in one place — the Base Account SDK for wallet, auth, and payments, and the Base Chain API for JSON-RPC, Flashblocks, and tracing.
@@ -67,11 +67,13 @@ npx skills add base/base-skills
6767
|base-chain/specs/upgrades/holocene:derivation,exec-engine,overview,system-config
6868
|base-chain/specs/upgrades/isthmus:derivation,exec-engine,l1-attributes,overview,predeploys,system-config
6969
|base-chain/specs/upgrades/jovian:derivation,exec-engine,l1-attributes,overview,system-config
70-
|build-on-base:lending-and-borrowing,overview,test-on-vibenet,tokenize-stocks
70+
|build-on-base:accept-b20-payment,overview,test-on-vibenet
7171
|build-on-base/agentic-payments:accept-a-payment,accept-subscriptions,collect-payer-info,pay-for-apis-with-x402,verify-a-payment
72+
|build-on-base/integrate-defi:integrate-borrowing,integrate-earn-product,integrate-lending
7273
|build-on-base/issue-stablecoins:block-an-account,burn-supply,issue-your-stablecoin,mint-supply,pause-activity,reconcile-with-memos,recover-funds,restrict-who-can-hold
7374
|build-on-base/ledgers:deposit,transfer,withdraw
74-
|get-started:agentic-payments,apis,apply-for-funding,base-batches,base-chain,base-ecosystem-fund,base-mentorship-program,base-services-hub,base,block-explorers,concepts,connect-to-base,country-leads-and-ambassadors,data-indexers,deploy-smart-contracts,docs-llms,docs-mcp,financing,get-funded,get-funds,issue-stablecoins,launch-b20-token,launch-token,learning-resources,lending-and-borrowing,make-a-transaction,private-transactions,prompt-library,resources-for-ai-agents,run-a-base-node,sdks-and-apis,sdks,tokenize-stocks
75+
|build-on-base/tokenize-stocks:announce-a-stock-dividend,cancel-blocked-shares,create-a-stock-token,issue-shares,pause-transfers,restrict-eligible-holders,run-a-stock-split
76+
|get-started:agentic-payments,apis,apply-for-funding,base-batches,base-chain,base-ecosystem-fund,base-mentorship-program,base-services-hub,base,block-explorers,concepts,connect-to-base,country-leads-and-ambassadors,data-indexers,deploy-smart-contracts,docs-llms,docs-mcp,financing,get-funded,get-funds,integrate-defi,issue-stablecoins,launch-b20-token,launch-token,learning-resources,make-a-transaction,private-transactions,prompt-library,resources-for-ai-agents,run-a-base-node,sdks-and-apis,sdks,tokenize-stocks
7577
|root:changes,contribution-guidelines,cookie-policy,privacy-policy,terms-of-service,tone_of_voice
7678
|sdks:overview
7779
|sdks/base-account:overview

docs/base-chain/node-operators/snapshots.mdx

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -130,11 +130,19 @@ Then continue from [**Start the Node**](#start-the-node) in the section above.
130130
## FAQ
131131

132132
<AccordionGroup>
133-
<Accordion title="Why does Base's Full snapshot use a different retention window than Reth's --full preset?">
133+
<Accordion title="What's the difference between a Full and Minimal node?">
134134

135135
In Reth, a "full" node is just a pruned node with a specific preset rather than a distinct node type. Reth's `--full` preset retains the last **10,064 blocks** (~1.4 days on Ethereum; ~5-6 hours on Base due to faster block times).
136136

137-
Base's `--full` snapshot uses a 31-day rolling retention window instead. If a smaller storage footprint is preferred, you can override `reth.toml` to match the 10,064-block preset.
137+
To read more about the difference between a Full and Minimal node, see the [Reth docs](https://reth.rs/run/storage/minimal).
138+
139+
</Accordion>
140+
141+
<Accordion title="How do I run my previous pruned node setup with v2 storage?">
142+
143+
If your v1-storage pruned node had a pruning distance of more than 10064 blocks, pull an Archival snapshot and then add the prune arguments.
144+
145+
The Full snapshot does not work for this migration because it only retains the last 10064 blocks.
138146

139147
</Accordion>
140148

docs/base-chain/quickstart/connecting-to-base.mdx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -77,16 +77,16 @@ Base is an EVM-compatible Layer 2 network. Use the details below to connect your
7777
<Tab title="Vibenet">
7878
Vibenet is Base's experimental preview network where new chain-level features are available before they roll out to Sepolia or Mainnet. It currently hosts [B20 tokens](/get-started/launch-b20-token) — an ERC-20 superset with built-in roles, supply caps, pausing, policy gating, and `permit` implemented as a native precompile.
7979

80-
Use Vibenet to build against cutting-edge Base features. It is not intended for production or user-facing applications. Learn more at [vibes.base.org](https://vibes.base.org).
80+
Use Vibenet to build against cutting-edge Base features. It is not intended for production or user-facing applications. Learn more at [chain.base.org/vibenet](https://chain.base.org/vibenet).
8181

8282
| | |
8383
| :--- | :--- |
8484
| **Network Name** | Base Vibenet |
8585
| **RPC Endpoint** | [rpc.vibes.base.org](https://rpc.vibes.base.org) |
8686
| **Chain ID** | 84538453 |
8787
| **Currency Symbol** | ETH |
88-
| **Faucet** | [faucet.vibes.base.org](https://faucet.vibes.base.org) |
89-
| **Block Explorer** | [explorer.vibes.base.org](https://explorer.vibes.base.org) |
88+
| **Faucet** | [chain.base.org/vibenet/faucet](https://chain.base.org/vibenet/faucet) |
89+
| **Block Explorer** | [chain.base.org/vibenet/explorer](https://chain.base.org/vibenet/explorer) |
9090

9191
</Tab>
9292
</Tabs>
@@ -129,7 +129,7 @@ The public Base endpoints are **HTTP only**. WebSocket RPC connections (`eth_sub
129129
<div style={{ display: 'flex', flexDirection: 'row', flexWrap: 'wrap', gap: '8px', marginTop: '12px' }}>
130130
<AddToMetaMask chainId="8453" chainName="Base Mainnet" rpcUrl="https://mainnet.base.org" blockExplorer="https://basescan.org" />
131131
<AddToMetaMask chainId="84532" chainName="Base Sepolia" rpcUrl="https://sepolia.base.org" blockExplorer="https://sepolia.basescan.org" />
132-
<AddToMetaMask chainId="84538453" chainName="Base Vibenet" rpcUrl="https://rpc.vibes.base.org" blockExplorer="https://explorer.vibes.base.org" />
132+
<AddToMetaMask chainId="84538453" chainName="Base Vibenet" rpcUrl="https://rpc.vibes.base.org" blockExplorer="https://chain.base.org/vibenet/explorer" />
133133
</div>
134134

135135
To add a network manually, use the details from the [Network details](#network-details) section above.

docs/base-chain/specs/upgrades/beryl/b20-playground.mdx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ A court order targets one account. Freeze it so it can't send, then seize the ba
2424

2525
## A customer pays an invoice
2626

27-
Your customer pays to one address. The transfer carries the invoice reference, so payment and order ID land in the same transaction. Reconciliation becomes a log query instead of a deposit address for every customer. To build this, see [Accept B20 payments](/build-on-base/agentic-payments/accept-a-payment).
27+
Your customer pays to one address. The transfer carries the invoice reference, so payment and order ID land in the same transaction. Reconciliation becomes a log query instead of a deposit address for every customer. To build this, see [Accept a B20 payment](/build-on-base/accept-b20-payment).
2828

2929
<Visibility for="humans">
3030
<B20FlowDemo flow="memo" />
@@ -52,7 +52,7 @@ A 2-for-1 split is one call. Every balance doubles without a migration or a new
5252
<Card title="Launch a B20 token" href="/get-started/launch-b20-token">
5353
Deploy a fully configured token in one factory call.
5454
</Card>
55-
<Card title="Accept B20 payments" href="/build-on-base/agentic-payments/accept-a-payment">
55+
<Card title="Accept a B20 payment" href="/build-on-base/accept-b20-payment">
5656
Integration code for memo-tagged payments and B20-specific reverts.
5757
</Card>
5858
<Card title="B20 native token standard" href="/base-chain/specs/upgrades/beryl/b20">

docs/base-chain/specs/upgrades/cobalt/eip-8130.mdx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ description: "Build with native account abstraction on Base. EIP-8130 smart acco
66
[EIP-8130](https://eip.tools/eip/8130) builds account abstraction into the protocol. An account registers who can act for it, and how its signatures are checked, in an onchain system contract. The chain validates each transaction against that configuration, so smart accounts work without bundlers, relays, or a separate mempool.
77

88
<Warning>
9-
EIP-8130 is experimental and currently runs only on the [vibenet devnet](https://vibes.base.org/build). You can learn more about connecting to vibenet [here](/base-chain/quickstart/connecting-to-base#vibenet).
9+
EIP-8130 is experimental and currently runs only on the [vibenet devnet](https://chain.base.org/vibenet). You can learn more about connecting to vibenet [here](/base-chain/quickstart/connecting-to-base#vibenet).
1010
</Warning>
1111

1212
## Build with EIP-8130
@@ -46,7 +46,7 @@ const signer = privateKeyToAccount(generatePrivateKey());
4646
const account = newSmartAccount8130({ signer });
4747

4848
// Fund it from the vibenet faucet
49-
await fetch("https://vibes.base.org/api/vibenet/faucet/drip", {
49+
await fetch("https://api.vibes.base.org/api/vibenet/faucet/drip", {
5050
method: "POST",
5151
headers: { "content-type": "application/json" },
5252
body: JSON.stringify({ address: account.address }),
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
---
2+
title: "Accept a B20 Payment"
3+
description: "Accept a B20 token payment and reconcile it to an order with an onchain memo."
4+
keywords: ["accept B20 payment", "transferWithMemo", "B20 token checkout", "reconcile token payment Base"]
5+
---
6+
7+
import { PaymentsDemo } from "/snippets/PaymentsDemo.jsx"
8+
9+
B20 is an ERC-20 superset, so standard token integrations work unchanged. Use `transferWithMemo` when you also need an order or invoice reference emitted beside the payment for reconciliation.
10+
11+
#### Demo
12+
13+
<PaymentsDemo flow="b20" />
14+
15+
## Pay and read the memo
16+
17+
Read the token's decimals, simulate the payment, then parse its `Memo` event from the confirmed receipt:
18+
19+
```ts pay-with-memo.ts lines wrap highlight={25-30,34-39}
20+
import {
21+
type Address,
22+
hexToString,
23+
parseEventLogs,
24+
parseUnits,
25+
stringToHex,
26+
} from 'viem';
27+
28+
const abi = [
29+
{ type: 'function', name: 'decimals', stateMutability: 'view', inputs: [], outputs: [{ type: 'uint8' }] },
30+
{ type: 'function', name: 'transferWithMemo', stateMutability: 'nonpayable', inputs: [
31+
{ name: 'to', type: 'address' },
32+
{ name: 'amount', type: 'uint256' },
33+
{ name: 'memo', type: 'bytes32' },
34+
], outputs: [{ type: 'bool' }] },
35+
{ type: 'event', name: 'Memo', inputs: [
36+
{ name: 'caller', type: 'address', indexed: true },
37+
{ name: 'memo', type: 'bytes32', indexed: true },
38+
] },
39+
] as const;
40+
41+
export async function payWithMemo(token: Address, merchant: Address) {
42+
const decimals = await publicClient.readContract({
43+
address: token, abi, functionName: 'decimals',
44+
});
45+
const payment = await publicClient.simulateContract({
46+
account: walletClient.account,
47+
address: token,
48+
abi,
49+
functionName: 'transferWithMemo',
50+
args: [merchant, parseUnits('25', decimals), stringToHex('order-8842', { size: 32 })],
51+
});
52+
const hash = await walletClient.writeContract(payment.request);
53+
const receipt = await publicClient.waitForTransactionReceipt({ hash });
54+
const [memo] = parseEventLogs({ abi, logs: receipt.logs, eventName: 'Memo' });
55+
56+
const orderId = hexToString(memo.args.memo, { size: 32 }).replace(/\0+$/, '');
57+
console.log(orderId); // "order-8842"
58+
}
59+
```
60+
61+
<Warning>
62+
A B20 transfer can revert when the issuer's holder policy denies the sender or recipient, or when transfers are paused. Simulate the exact call and surface the decoded reason before asking the user to sign.
63+
</Warning>
64+
65+
## See also
66+
67+
- [Reconcile stablecoin activity with memos](/build-on-base/issue-stablecoins/reconcile-with-memos)
68+
- [B20 memos](/base-chain/specs/upgrades/beryl/b20#memos) and [Launch a B20 token](/get-started/launch-b20-token)
Lines changed: 186 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,186 @@
1+
---
2+
title: "Integrate Borrowing"
3+
description: "Let users borrow USDC against WETH collateral with Morpho, Moonwell, or Aave on Base."
4+
keywords: ["integrate borrowing Base", "borrow USDC against WETH", "Morpho borrow", "Moonwell borrow", "Aave borrow Base"]
5+
---
6+
7+
import { DeFiDemo } from "/snippets/DeFiDemo.jsx"
8+
9+
Open a collateralized loan through a third-party protocol on Base. A safe integration shows collateral value, debt, liquidation parameters, and health before and after every user-signed action.
10+
11+
#### Demo
12+
13+
<DeFiDemo flow="borrow" />
14+
15+
## Supply collateral and borrow
16+
17+
These examples use `viem@2.55.11`, `@morpho-org/morpho-sdk@5.4.1`, `@moonwell-fi/moonwell-sdk@0.22.0`, and `@aave-dao/aave-address-book@4.65.5`.
18+
19+
<Tabs>
20+
<Tab title="Morpho">
21+
Prepare one Morpho bundle that supplies WETH collateral and borrows USDC from the WETH/USDC market.
22+
23+
```ts borrow-morpho.ts lines wrap highlight={15-23,33-35}
24+
import { type MarketId } from '@morpho-org/blue-sdk';
25+
import { fetchMarketParams } from '@morpho-org/blue-sdk-viem';
26+
import {
27+
isRequirementSignature,
28+
morphoViemExtension,
29+
} from '@morpho-org/morpho-sdk';
30+
import { parseUnits } from 'viem';
31+
import { base } from 'viem/chains';
32+
33+
const marketId =
34+
'0x8793cf302b8ffd655ab97bd1c695dbd967807e8367a65cb2f4edaf1380ba1bda' as MarketId;
35+
const user = walletClient.account.address;
36+
const client = publicClient.extend(morphoViemExtension());
37+
const params = await fetchMarketParams(marketId, publicClient);
38+
const market = client.morpho.blue(params, base.id);
39+
const positionData = await market.getPositionData(user);
40+
const action = market.supplyCollateralBorrow({
41+
amount: parseUnits('2', 18),
42+
borrowAmount: parseUnits('2000', 6),
43+
userAddress: user,
44+
positionData,
45+
});
46+
47+
const signatures = [];
48+
for (const requirement of await action.getRequirements()) {
49+
if (isRequirementSignature(requirement)) {
50+
signatures.push(await requirement.sign(walletClient, user));
51+
} else {
52+
const hash = await walletClient.sendTransaction(requirement);
53+
await publicClient.waitForTransactionReceipt({ hash });
54+
}
55+
}
56+
const request = action.buildTx(signatures);
57+
await publicClient.call({ account: user, ...request });
58+
const hash = await walletClient.sendTransaction(request);
59+
await publicClient.waitForTransactionReceipt({ hash });
60+
```
61+
</Tab>
62+
63+
<Tab title="Moonwell">
64+
Supply WETH to its market, enter that market as collateral, then borrow from the USDC market.
65+
66+
```ts borrow-moonwell.ts lines wrap highlight={19-25,27-34}
67+
import { createMoonwellClient } from '@moonwell-fi/moonwell-sdk';
68+
import { parseAbi, parseUnits } from 'viem';
69+
70+
const env = createMoonwellClient({
71+
networks: { base: { rpcUrls: ['https://mainnet.base.org'] } },
72+
}).environments.base;
73+
const weth = env.tokens.WETH.address;
74+
const mWeth = env.tokens.MOONWELL_ETH.address;
75+
const mUsdc = env.tokens.MOONWELL_USDC.address;
76+
const comptroller = env.contracts.comptroller.address;
77+
const user = walletClient.account;
78+
79+
const erc20Abi = parseAbi(['function approve(address,uint256) returns (bool)']);
80+
const marketAbi = parseAbi([
81+
'function mint(uint256) returns (uint256)',
82+
'function borrow(uint256) returns (uint256)',
83+
]);
84+
const comptrollerAbi = parseAbi([
85+
'function enterMarkets(address[]) returns (uint256[])',
86+
]);
87+
88+
const approval = await publicClient.simulateContract({
89+
account: user, address: weth, abi: erc20Abi, functionName: 'approve',
90+
args: [mWeth, parseUnits('2', 18)],
91+
});
92+
await publicClient.waitForTransactionReceipt({
93+
hash: await walletClient.writeContract(approval.request),
94+
});
95+
96+
const supplied = await publicClient.simulateContract({
97+
account: user, address: mWeth, abi: marketAbi, functionName: 'mint',
98+
args: [parseUnits('2', 18)],
99+
});
100+
if (supplied.result !== 0n) throw new Error(`Moonwell error ${supplied.result}`);
101+
await publicClient.waitForTransactionReceipt({
102+
hash: await walletClient.writeContract(supplied.request),
103+
});
104+
105+
const entered = await publicClient.simulateContract({
106+
account: user, address: comptroller, abi: comptrollerAbi,
107+
functionName: 'enterMarkets', args: [[mWeth]],
108+
});
109+
if (entered.result.some((code) => code !== 0n)) throw new Error('enterMarkets failed');
110+
await publicClient.waitForTransactionReceipt({
111+
hash: await walletClient.writeContract(entered.request),
112+
});
113+
114+
const loan = await publicClient.simulateContract({
115+
account: user, address: mUsdc, abi: marketAbi, functionName: 'borrow',
116+
args: [parseUnits('2000', 6)],
117+
});
118+
if (loan.result !== 0n) throw new Error(`Moonwell error ${loan.result}`);
119+
await publicClient.waitForTransactionReceipt({
120+
hash: await walletClient.writeContract(loan.request),
121+
});
122+
```
123+
</Tab>
124+
125+
<Tab title="Aave">
126+
Use Aave's official address book with the Base Aave V3 Pool. Supply WETH, explicitly enable it as collateral, then borrow USDC at the variable rate.
127+
128+
```ts borrow-aave.ts lines wrap highlight={13-19,31-37}
129+
import { AaveV3Base } from '@aave-dao/aave-address-book';
130+
import { parseAbi, parseUnits } from 'viem';
131+
132+
const user = walletClient.account;
133+
const weth = AaveV3Base.ASSETS.WETH.UNDERLYING;
134+
const usdc = AaveV3Base.ASSETS.USDC.UNDERLYING;
135+
const collateral = parseUnits('2', 18);
136+
const erc20Abi = parseAbi(['function approve(address,uint256) returns (bool)']);
137+
const poolAbi = parseAbi([
138+
'function supply(address,uint256,address,uint16)',
139+
'function setUserUseReserveAsCollateral(address,bool)',
140+
'function borrow(address,uint256,uint256,uint16,address)',
141+
]);
142+
143+
const approval = await publicClient.simulateContract({
144+
account: user, address: weth, abi: erc20Abi, functionName: 'approve',
145+
args: [AaveV3Base.POOL, collateral],
146+
});
147+
await publicClient.waitForTransactionReceipt({
148+
hash: await walletClient.writeContract(approval.request),
149+
});
150+
151+
const supplied = await publicClient.simulateContract({
152+
account: user, address: AaveV3Base.POOL, abi: poolAbi,
153+
functionName: 'supply', args: [weth, collateral, user.address, 0],
154+
});
155+
await publicClient.waitForTransactionReceipt({
156+
hash: await walletClient.writeContract(supplied.request),
157+
});
158+
159+
const enabled = await publicClient.simulateContract({
160+
account: user, address: AaveV3Base.POOL, abi: poolAbi,
161+
functionName: 'setUserUseReserveAsCollateral', args: [weth, true],
162+
});
163+
await publicClient.waitForTransactionReceipt({
164+
hash: await walletClient.writeContract(enabled.request),
165+
});
166+
167+
const loan = await publicClient.simulateContract({
168+
account: user, address: AaveV3Base.POOL, abi: poolAbi,
169+
functionName: 'borrow',
170+
args: [usdc, parseUnits('2000', 6), 2n, 0, user.address],
171+
});
172+
await publicClient.waitForTransactionReceipt({
173+
hash: await walletClient.writeContract(loan.request),
174+
});
175+
```
176+
</Tab>
177+
</Tabs>
178+
179+
<Warning>
180+
Collateral prices, oracle updates, interest, and protocol parameters can move a position toward liquidation. Re-fetch and display health immediately before signing, and warn clearly before a transaction creates unsafe debt.
181+
</Warning>
182+
183+
## See also
184+
185+
- [Integrate lending](/build-on-base/integrate-defi/integrate-lending) · [Integrate an earn product](/build-on-base/integrate-defi/integrate-earn-product)
186+
- [Integrate DeFi overview](/get-started/integrate-defi)

0 commit comments

Comments
 (0)