Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 8 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ Skills are drop-in modules. No additional configuration required for basic usage
| botchan | [botchan](botchan/) | Onchain messaging protocol on Base. Agent feeds, DMs, permanent data storage. |
| [qrcoin](https://qrcoin.fun) | [qrcoin](qrcoin/) | QR code auction platform on Base. Programmatic bidding for URL display. |
| yoink | [yoink](yoink/) | Onchain capture-the-flag on Base. |
| base | — | Planned |
| [base](https://base.org) | [base](base/) | Smart contract development on Base. Deploy contracts, manage wallets, agent-to-agent payments. |
| neynar | — | Planned |
| zapper | — | Planned |

Expand All @@ -44,8 +44,13 @@ openclaw-skills/
│ └── scripts/
│ └── bankr.sh
├── base/ # Base (placeholder)
│ └── SKILL.md
├── base/ # Base
│ ├── SKILL.md
│ └── references/
│ ├── cdp-setup.md
│ ├── deployment.md
│ ├── testing.md
│ └── ...
├── neynar/ # Neynar (placeholder)
│ └── SKILL.md
├── qrcoin/ # QR Coin (community)
Expand Down
41 changes: 40 additions & 1 deletion base/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,43 @@
---
name: base
description: Placeholder for Base skill.
description: Build on Base blockchain. Use for smart contract development, deployment, wallet management, and agent-to-agent financial agreements. Routes to sub-skills for specific tasks.
---

# Base

Build on Base blockchain using Foundry and CDP SDK.

**Security**: Uses CDP managed wallets. Agent never accesses private keys.

## Sub-Skills

| Task | Reference | Use When |
|------|-----------|----------|
| Wallet Setup | [cdp-setup.md](references/cdp-setup.md) | Creating wallets, CDP authentication |
| Testnet Faucet | [cdp-faucet.md](references/cdp-faucet.md) | Getting Base Sepolia test ETH |
| Contract Dev | [contract-development.md](references/contract-development.md) | Writing Solidity contracts |
| Testing | [testing.md](references/testing.md) | Testing with Foundry |
| Deployment | [deployment.md](references/deployment.md) | Deploying to Base |
| Verification | [verification.md](references/verification.md) | Verifying on Basescan |
| Interaction | [contract-interaction.md](references/contract-interaction.md) | Reading/writing contracts |
| Agent Patterns | [agent-patterns.md](references/agent-patterns.md) | Escrow, payments, tokens |

## Networks

| Network | ID | Chain ID |
|---------|-----|----------|
| Base Mainnet | `base` | 8453 |
| Base Sepolia | `base-sepolia` | 84532 |

## Quick Reference

```bash
# Install
curl -L https://foundry.paradigm.xyz | bash && foundryup
npm install @coinbase/cdp-sdk

# Build & test
forge build && forge test

# Deploy (see deployment.md)
```
153 changes: 153 additions & 0 deletions base/references/agent-patterns.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
# Agent-to-Agent Patterns

Smart contract patterns for agent-to-agent transactions.

## When to Use

Deploy a contract when agents need:
- Trustless payment agreements
- Automatic revenue splits
- Escrow for deliverables
- Custom tokens for agent economy

## Escrow Contract

Hold funds until conditions met.

```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;

contract SimpleEscrow {
address public payer;
address public payee;
uint256 public amount;
bool public released;

constructor(address _payee) payable {
payer = msg.sender;
payee = _payee;
amount = msg.value;
}

function release() external {
require(msg.sender == payer, "Only payer");
require(!released, "Already released");
released = true;
payable(payee).transfer(amount);
}

function refund() external {
require(msg.sender == payee, "Only payee");
require(!released, "Already released");
released = true;
payable(payer).transfer(amount);
}
}
```

**Deploy with value:**
```typescript
const { transactionHash } = await cdp.evm.sendTransaction({
address: account.address,
network: "base-sepolia",
transaction: {
to: undefined,
data: bytecode + encodedPayeeAddress,
value: parseEther("0.1"),
},
});
```

## Payment Splitter

Automatic revenue distribution.

```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;

import "@openzeppelin/contracts/finance/PaymentSplitter.sol";

contract RevenueSplit is PaymentSplitter {
constructor(
address[] memory payees,
uint256[] memory shares_
) PaymentSplitter(payees, shares_) {}
}
```

**Deploy for 60/40 split:**
```typescript
const payees = ["0xAgent1...", "0xAgent2..."];
const shares = [60, 40];
// Encode and deploy...
```

## Simple Token

Custom ERC-20 for agent economy.

```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;

import "@openzeppelin/contracts/token/ERC20/ERC20.sol";

contract AgentToken is ERC20 {
constructor(uint256 initialSupply) ERC20("AgentToken", "AGT") {
_mint(msg.sender, initialSupply);
}
}
```

## Conditional Payment

Pay when condition is verified.

```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;

contract ConditionalPayment {
address public payer;
address public payee;
address public arbiter;
uint256 public amount;
bool public completed;

constructor(address _payee, address _arbiter) payable {
payer = msg.sender;
payee = _payee;
arbiter = _arbiter;
amount = msg.value;
}

function approve() external {
require(msg.sender == arbiter, "Only arbiter");
require(!completed, "Already completed");
completed = true;
payable(payee).transfer(amount);
}

function reject() external {
require(msg.sender == arbiter, "Only arbiter");
require(!completed, "Already completed");
completed = true;
payable(payer).transfer(amount);
}
}
```

## Workflow

1. Agents negotiate terms
2. One agent deploys contract with terms encoded
3. Other agent verifies contract source
4. Funds deposited
5. Conditions met → funds released

## Resources

- [OpenZeppelin PaymentSplitter](https://docs.openzeppelin.com/contracts/4.x/api/finance#PaymentSplitter)
- [OpenZeppelin ERC20](https://docs.openzeppelin.com/contracts/4.x/erc20)
116 changes: 116 additions & 0 deletions base/references/cdp-faucet.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
# CDP Faucet - Testnet ETH

Request testnet ETH programmatically via the CDP SDK.

## Using CDP SDK (Recommended)

The CDP SDK provides a simple method to request testnet funds:

```typescript
import { CdpClient } from "@coinbase/cdp-sdk";

const cdp = new CdpClient();

// Get or create your wallet
const account = await cdp.evm.getOrCreateAccount({
name: "my-agent-wallet",
});

// Request testnet ETH
const faucetResp = await cdp.evm.requestFaucet({
address: account.address,
network: "base-sepolia",
token: "eth",
});

console.log("Faucet transaction:", faucetResp.transactionHash);
```

## Supported Networks

| Network | Network ID | Token |
|---------|------------|-------|
| Base Sepolia | `base-sepolia` | `eth` |
| Ethereum Sepolia | `ethereum-sepolia` | `eth` |

## Complete Example

```typescript
import { CdpClient } from "@coinbase/cdp-sdk";

async function fundWallet() {
const cdp = new CdpClient();

// Create or get wallet
const account = await cdp.evm.getOrCreateAccount({
name: "deployer",
});

console.log("Wallet address:", account.address);

// Check current balance
const balance = await cdp.evm.getBalance({
address: account.address,
network: "base-sepolia",
});

console.log("Current balance:", balance.amount);

// Request faucet if balance is low
if (BigInt(balance.amount) < BigInt("100000000000000000")) { // 0.1 ETH
console.log("Requesting faucet...");

const faucetResp = await cdp.evm.requestFaucet({
address: account.address,
network: "base-sepolia",
token: "eth",
});

console.log("Faucet tx:", faucetResp.transactionHash);
console.log("View:", `https://sepolia.basescan.org/tx/${faucetResp.transactionHash}`);

// Wait for confirmation
await new Promise(r => setTimeout(r, 5000));

// Check new balance
const newBalance = await cdp.evm.getBalance({
address: account.address,
network: "base-sepolia",
});

console.log("New balance:", newBalance.amount);
} else {
console.log("Sufficient balance, no faucet needed");
}
}

fundWallet().catch(console.error);
```

## Rate Limits

The CDP faucet has rate limits to prevent abuse:
- Limited requests per address per day
- If rate limited, wait before retrying

## Alternative Faucets

If CDP faucet is unavailable or rate limited:

- **Alchemy Faucet**: https://www.alchemy.com/faucets/base-sepolia
- **QuickNode Faucet**: https://faucet.quicknode.com/base/sepolia
- **Chainlink Faucet**: https://faucets.chain.link/base-sepolia

## Troubleshooting

**"Rate limited"**
- Wait before retrying
- Use alternative faucets listed above

**"Network not supported"**
- Verify network is exactly `base-sepolia`
- Faucet only works for testnets

**"Authentication error"**
- Check CDP_API_KEY_ID and CDP_API_KEY_SECRET
- Ensure environment variables are set correctly
Loading
Loading