Skip to content

Commit cfcd318

Browse files
author
h1-hunt
committed
feat: add Mint Club V2 action provider
Add action provider for Mint Club V2 bonding curve protocol on Base. Actions: - get_token_info: Token details and bonding curve information - get_token_price: Current price in reserve tokens and USD - buy_token: Mint tokens via bonding curve - sell_token: Burn tokens via bonding curve - create_token: Create new token with bonding curve Uses viem for direct contract interaction with MCV2_Bond. Includes auto ERC20 approval, slippage protection, and USD pricing via 1inch Spot Price Aggregator. Docs: https://docs.mint.club Protocol: https://mint.club
1 parent e44e0e4 commit cfcd318

8 files changed

Lines changed: 1519 additions & 0 deletions

File tree

typescript/agentkit/src/action-providers/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ export * from "./erc721";
1818
export * from "./farcaster";
1919
export * from "./jupiter";
2020
export * from "./messari";
21+
export * from "./mintclub";
2122
export * from "./pyth";
2223
export * from "./moonwell";
2324
export * from "./morpho";
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
# Mint Club V2 Action Provider
2+
3+
This directory contains the **MintclubActionProvider** implementation, which provides actions to interact with the **Mint Club V2 protocol** on Base mainnet.
4+
5+
## Directory Structure
6+
7+
```
8+
mintclub/
9+
├── mintclubActionProvider.ts # Main provider with Mint Club V2 functionality
10+
├── mintclubActionProvider.test.ts # Test file for Mint Club provider
11+
├── constants.ts # Mint Club contract constants and ABIs
12+
├── schemas.ts # Mint Club action schemas
13+
├── utils.ts # Mint Club utility functions
14+
├── index.ts # Main exports
15+
└── README.md # This file
16+
```
17+
18+
## Actions
19+
20+
- `get_token_info`: Get detailed information about a Mint Club token including bonding curve details
21+
- `get_token_price`: Get the current price of a Mint Club token in reserve tokens and USD
22+
- `buy_token`: Buy Mint Club tokens via the bonding curve mechanism
23+
- `sell_token`: Sell Mint Club tokens via the bonding curve mechanism
24+
- `create_token`: Create a new Mint Club token with bonding curve
25+
26+
## Adding New Actions
27+
28+
To add new Mint Club actions:
29+
30+
1. Define your action schema in `schemas.ts`
31+
2. Implement the action in `mintclubActionProvider.ts`
32+
3. Add tests in `mintclubActionProvider.test.ts`
33+
34+
## Network Support
35+
36+
The Mint Club provider supports Base mainnet only.
37+
38+
## Notes
39+
40+
Mint Club V2 is a bonding curve token protocol that allows anyone to create tokens backed by reserve assets. The protocol uses mathematical curves to determine token prices based on supply and demand.
41+
42+
For more information on the **Mint Club V2 protocol**, visit [Mint Club Documentation](https://mint.club/).
Lines changed: 252 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,252 @@
1+
import type { Abi } from "abitype";
2+
3+
export const SUPPORTED_NETWORKS = ["base-mainnet"];
4+
5+
/**
6+
* MCV2 Bond contract ABI - minimal functions needed for Mint Club V2 interactions.
7+
*/
8+
export const MCV2_BOND_ABI: Abi = [
9+
{
10+
type: "function",
11+
name: "tokenBond",
12+
inputs: [{ name: "token", type: "address", internalType: "address" }],
13+
outputs: [
14+
{ name: "creator", type: "address", internalType: "address" },
15+
{ name: "mintRoyalty", type: "uint16", internalType: "uint16" },
16+
{ name: "burnRoyalty", type: "uint16", internalType: "uint16" },
17+
{ name: "createdAt", type: "uint40", internalType: "uint40" },
18+
{ name: "reserveToken", type: "address", internalType: "address" },
19+
{ name: "reserveBalance", type: "uint256", internalType: "uint256" },
20+
],
21+
stateMutability: "view",
22+
},
23+
{
24+
type: "function",
25+
name: "getReserveForToken",
26+
inputs: [
27+
{ name: "token", type: "address", internalType: "address" },
28+
{ name: "tokensToMint", type: "uint256", internalType: "uint256" },
29+
],
30+
outputs: [
31+
{ name: "reserveAmount", type: "uint256", internalType: "uint256" },
32+
{ name: "royalty", type: "uint256", internalType: "uint256" },
33+
],
34+
stateMutability: "view",
35+
},
36+
{
37+
type: "function",
38+
name: "getRefundForTokens",
39+
inputs: [
40+
{ name: "token", type: "address", internalType: "address" },
41+
{ name: "tokensToBurn", type: "uint256", internalType: "uint256" },
42+
],
43+
outputs: [
44+
{ name: "refundAmount", type: "uint256", internalType: "uint256" },
45+
{ name: "royalty", type: "uint256", internalType: "uint256" },
46+
],
47+
stateMutability: "view",
48+
},
49+
{
50+
type: "function",
51+
name: "mint",
52+
inputs: [
53+
{ name: "token", type: "address", internalType: "address" },
54+
{ name: "tokensToMint", type: "uint256", internalType: "uint256" },
55+
{ name: "maxReserveAmount", type: "uint256", internalType: "uint256" },
56+
{ name: "receiver", type: "address", internalType: "address" },
57+
],
58+
outputs: [{ name: "", type: "uint256", internalType: "uint256" }],
59+
stateMutability: "nonpayable",
60+
},
61+
{
62+
type: "function",
63+
name: "burn",
64+
inputs: [
65+
{ name: "token", type: "address", internalType: "address" },
66+
{ name: "tokensToBurn", type: "uint256", internalType: "uint256" },
67+
{ name: "minRefund", type: "uint256", internalType: "uint256" },
68+
{ name: "receiver", type: "address", internalType: "address" },
69+
],
70+
outputs: [{ name: "", type: "uint256", internalType: "uint256" }],
71+
stateMutability: "nonpayable",
72+
},
73+
{
74+
type: "function",
75+
name: "createToken",
76+
inputs: [
77+
{
78+
name: "tp",
79+
type: "tuple",
80+
internalType: "struct MCV2_Bond.TokenParams",
81+
components: [
82+
{ name: "name", type: "string", internalType: "string" },
83+
{ name: "symbol", type: "string", internalType: "string" },
84+
],
85+
},
86+
{
87+
name: "bp",
88+
type: "tuple",
89+
internalType: "struct MCV2_Bond.BondParams",
90+
components: [
91+
{ name: "mintRoyalty", type: "uint16", internalType: "uint16" },
92+
{ name: "burnRoyalty", type: "uint16", internalType: "uint16" },
93+
{ name: "reserveToken", type: "address", internalType: "address" },
94+
{ name: "maxSupply", type: "uint128", internalType: "uint128" },
95+
{ name: "stepRanges", type: "uint128[]", internalType: "uint128[]" },
96+
{ name: "stepPrices", type: "uint128[]", internalType: "uint128[]" },
97+
],
98+
},
99+
],
100+
outputs: [{ name: "token", type: "address", internalType: "address" }],
101+
stateMutability: "payable",
102+
},
103+
{
104+
type: "function",
105+
name: "creationFee",
106+
inputs: [],
107+
outputs: [{ name: "", type: "uint256", internalType: "uint256" }],
108+
stateMutability: "view",
109+
},
110+
] as const;
111+
112+
/**
113+
* ERC20 token ABI - standard functions needed for token interactions.
114+
*/
115+
export const ERC20_ABI: Abi = [
116+
{
117+
type: "function",
118+
name: "symbol",
119+
inputs: [],
120+
outputs: [{ name: "", type: "string", internalType: "string" }],
121+
stateMutability: "view",
122+
},
123+
{
124+
type: "function",
125+
name: "decimals",
126+
inputs: [],
127+
outputs: [{ name: "", type: "uint8", internalType: "uint8" }],
128+
stateMutability: "view",
129+
},
130+
{
131+
type: "function",
132+
name: "totalSupply",
133+
inputs: [],
134+
outputs: [{ name: "", type: "uint256", internalType: "uint256" }],
135+
stateMutability: "view",
136+
},
137+
{
138+
type: "function",
139+
name: "balanceOf",
140+
inputs: [{ name: "account", type: "address", internalType: "address" }],
141+
outputs: [{ name: "", type: "uint256", internalType: "uint256" }],
142+
stateMutability: "view",
143+
},
144+
{
145+
type: "function",
146+
name: "approve",
147+
inputs: [
148+
{ name: "spender", type: "address", internalType: "address" },
149+
{ name: "amount", type: "uint256", internalType: "uint256" },
150+
],
151+
outputs: [{ name: "", type: "bool", internalType: "bool" }],
152+
stateMutability: "nonpayable",
153+
},
154+
{
155+
type: "function",
156+
name: "allowance",
157+
inputs: [
158+
{ name: "owner", type: "address", internalType: "address" },
159+
{ name: "spender", type: "address", internalType: "address" },
160+
],
161+
outputs: [{ name: "", type: "uint256", internalType: "uint256" }],
162+
stateMutability: "view",
163+
},
164+
] as const;
165+
166+
/**
167+
* 1inch Spot Price Aggregator ABI for USD pricing.
168+
*/
169+
export const SPOT_PRICE_AGGREGATOR_ABI: Abi = [
170+
{
171+
type: "function",
172+
name: "getRate",
173+
inputs: [
174+
{ name: "srcToken", type: "address", internalType: "contract IERC20" },
175+
{ name: "dstToken", type: "address", internalType: "contract IERC20" },
176+
{ name: "useWrappers", type: "bool", internalType: "bool" },
177+
],
178+
outputs: [{ name: "weightedRate", type: "uint256", internalType: "uint256" }],
179+
stateMutability: "view",
180+
},
181+
] as const;
182+
183+
/**
184+
* Contract addresses on Base mainnet.
185+
*/
186+
export const MINTCLUB_CONTRACT_ADDRESSES = {
187+
"base-mainnet": {
188+
MCV2_Bond: "0xc5a076cad94176c2996B32d8466Be1cE757FAa27",
189+
SpotPriceAggregator: "0x00000000000D6FFc74A8feb35aF5827bf57f6786",
190+
USDC: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
191+
},
192+
} as const;
193+
194+
/**
195+
* Gets the MCV2 Bond contract address for the specified network.
196+
*
197+
* @param network - The network ID to get the contract address for.
198+
* @returns The contract address for the specified network.
199+
* @throws Error if the specified network is not supported.
200+
*/
201+
export function getBondAddress(network: string): string {
202+
const addresses =
203+
MINTCLUB_CONTRACT_ADDRESSES[
204+
network.toLowerCase() as keyof typeof MINTCLUB_CONTRACT_ADDRESSES
205+
];
206+
if (!addresses) {
207+
throw new Error(
208+
`Unsupported network: ${network}. Supported: ${Object.keys(MINTCLUB_CONTRACT_ADDRESSES).join(", ")}`,
209+
);
210+
}
211+
return addresses.MCV2_Bond;
212+
}
213+
214+
/**
215+
* Gets the Spot Price Aggregator contract address for the specified network.
216+
*
217+
* @param network - The network ID to get the contract address for.
218+
* @returns The contract address for the specified network.
219+
* @throws Error if the specified network is not supported.
220+
*/
221+
export function getSpotPriceAggregatorAddress(network: string): string {
222+
const addresses =
223+
MINTCLUB_CONTRACT_ADDRESSES[
224+
network.toLowerCase() as keyof typeof MINTCLUB_CONTRACT_ADDRESSES
225+
];
226+
if (!addresses) {
227+
throw new Error(
228+
`Unsupported network: ${network}. Supported: ${Object.keys(MINTCLUB_CONTRACT_ADDRESSES).join(", ")}`,
229+
);
230+
}
231+
return addresses.SpotPriceAggregator;
232+
}
233+
234+
/**
235+
* Gets the USDC contract address for the specified network.
236+
*
237+
* @param network - The network ID to get the contract address for.
238+
* @returns The contract address for the specified network.
239+
* @throws Error if the specified network is not supported.
240+
*/
241+
export function getUsdcAddress(network: string): string {
242+
const addresses =
243+
MINTCLUB_CONTRACT_ADDRESSES[
244+
network.toLowerCase() as keyof typeof MINTCLUB_CONTRACT_ADDRESSES
245+
];
246+
if (!addresses) {
247+
throw new Error(
248+
`Unsupported network: ${network}. Supported: ${Object.keys(MINTCLUB_CONTRACT_ADDRESSES).join(", ")}`,
249+
);
250+
}
251+
return addresses.USDC;
252+
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
export * from "./schemas";
2+
export * from "./mintclubActionProvider";

0 commit comments

Comments
 (0)