@four-meme/four-meme-ai 1.0.4 → 1.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CLAUDE.md +91 -91
- package/README.md +136 -108
- package/bin/fourmeme.cjs +171 -128
- package/package.json +2 -1
- package/skills/four-meme-integration/SKILL.md +18 -25
- package/skills/four-meme-integration/references/agent-creator-and-wallets.md +87 -0
- package/skills/four-meme-integration/references/api-create-token.md +55 -55
- package/skills/four-meme-integration/references/contract-addresses.md +47 -34
- package/skills/four-meme-integration/references/create-token-scripts.md +111 -63
- package/skills/four-meme-integration/references/errors.md +29 -27
- package/skills/four-meme-integration/references/event-listening.md +75 -75
- package/skills/four-meme-integration/references/execute-trade.md +31 -31
- package/skills/four-meme-integration/references/tax-token-query.md +38 -38
- package/skills/four-meme-integration/references/token-tax-info.md +77 -77
- package/skills/four-meme-integration/scripts/8004-balance.ts +52 -52
- package/skills/four-meme-integration/scripts/8004-register.ts +108 -108
- package/skills/four-meme-integration/scripts/create-token-api.ts +321 -251
- package/skills/four-meme-integration/scripts/create-token-chain.ts +102 -85
- package/skills/four-meme-integration/scripts/create-token-instant.ts +106 -0
- package/skills/four-meme-integration/scripts/execute-buy.ts +198 -198
- package/skills/four-meme-integration/scripts/execute-sell.ts +150 -150
- package/skills/four-meme-integration/scripts/send-token.ts +98 -98
|
@@ -1,77 +1,77 @@
|
|
|
1
|
-
# Tax Token parameters (tokenTaxInfo)
|
|
2
|
-
|
|
3
|
-
When creating a **Tax-type token**, send a `tokenTaxInfo` object in the create request body. If omitted, a normal token is created. Agent interaction (whether to create a tax token, parameter order) is in [SKILL.md](../SKILL.md) “Create token (full flow)”. This page only lists fields and constraints.
|
|
4
|
-
|
|
5
|
-
## Field summary
|
|
6
|
-
|
|
7
|
-
| Parameter | Type | Description | Allowed values / constraint |
|
|
8
|
-
|-----------|------|-------------|------------------------------|
|
|
9
|
-
| **feeRate** | number | Trading fee rate (%) | **Exactly one of**: `1`, `3`, `5`, `10` |
|
|
10
|
-
| **burnRate** | number | Burn share (%) | Custom; see constraints below |
|
|
11
|
-
| **divideRate** | number | Dividend share (%) | Custom; see below |
|
|
12
|
-
| **liquidityRate** | number | Liquidity share (%) | Custom; see below |
|
|
13
|
-
| **recipientRate** | number | Recipient share (%) | Custom; use `0` if not used |
|
|
14
|
-
| **recipientAddress** | string | Address that receives allocation | Use `""` if not used |
|
|
15
|
-
| **minSharing** | number | Min balance for dividends (ether units) | Must satisfy `d × 10ⁿ`, n≥5, 1≤d≤9 |
|
|
16
|
-
|
|
17
|
-
## Constraints
|
|
18
|
-
|
|
19
|
-
1. **feeRate** must be one of **1, 3, 5, 10** (1%, 3%, 5%, 10%).
|
|
20
|
-
2. **burnRate + divideRate + liquidityRate + recipientRate = 100** (the four shares must sum to 100).
|
|
21
|
-
3. If no recipient: **recipientAddress = ""** and **recipientRate = 0**.
|
|
22
|
-
4. **minSharing** examples: `100000` (1×10⁵), `200000`, `500000`, `1000000` (1×10⁶), `9000000`, `10000000` (1×10⁷), i.e. `d × 10ⁿ` with n≥5, 1≤d≤9.
|
|
23
|
-
|
|
24
|
-
## Examples
|
|
25
|
-
|
|
26
|
-
**Example 1: 5% fee, 20% burn, 30% dividend, 40% liquidity, 10% recipient**
|
|
27
|
-
|
|
28
|
-
```json
|
|
29
|
-
{
|
|
30
|
-
"tokenTaxInfo": {
|
|
31
|
-
"feeRate": 5,
|
|
32
|
-
"burnRate": 20,
|
|
33
|
-
"divideRate": 30,
|
|
34
|
-
"liquidityRate": 40,
|
|
35
|
-
"recipientRate": 10,
|
|
36
|
-
"recipientAddress": "0x1234567890123456789012345678901234567890",
|
|
37
|
-
"minSharing": 100000
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
```
|
|
41
|
-
|
|
42
|
-
**Example 2: 3% fee, 100% liquidity, no dividend/burn/recipient**
|
|
43
|
-
|
|
44
|
-
```json
|
|
45
|
-
{
|
|
46
|
-
"tokenTaxInfo": {
|
|
47
|
-
"feeRate": 3,
|
|
48
|
-
"burnRate": 0,
|
|
49
|
-
"divideRate": 0,
|
|
50
|
-
"liquidityRate": 100,
|
|
51
|
-
"recipientRate": 0,
|
|
52
|
-
"recipientAddress": "",
|
|
53
|
-
"minSharing": 100000
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
```
|
|
57
|
-
|
|
58
|
-
**Example 3: 10% fee, 50% dividend, 50% burn, min share 1×10⁶**
|
|
59
|
-
|
|
60
|
-
```json
|
|
61
|
-
{
|
|
62
|
-
"tokenTaxInfo": {
|
|
63
|
-
"feeRate": 10,
|
|
64
|
-
"burnRate": 50,
|
|
65
|
-
"divideRate": 50,
|
|
66
|
-
"liquidityRate": 0,
|
|
67
|
-
"recipientRate": 0,
|
|
68
|
-
"recipientAddress": "",
|
|
69
|
-
"minSharing": 1000000
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
```
|
|
73
|
-
|
|
74
|
-
## Use in scripts
|
|
75
|
-
|
|
76
|
-
- **Option 1 (recommended)**: Write the above `tokenTaxInfo` to a JSON file (can contain only `tokenTaxInfo`) and pass that file path as the last argument to `create-token-api.ts`; the script merges it into the create body.
|
|
77
|
-
- **Option 2**: Build tax params via env vars (see “Create token (API)” optional env in SKILL.md).
|
|
1
|
+
# Tax Token parameters (tokenTaxInfo)
|
|
2
|
+
|
|
3
|
+
When creating a **Tax-type token**, send a `tokenTaxInfo` object in the create request body. If omitted, a normal token is created. Agent interaction (whether to create a tax token, parameter order) is in [SKILL.md](../SKILL.md) “Create token (full flow)”. This page only lists fields and constraints.
|
|
4
|
+
|
|
5
|
+
## Field summary
|
|
6
|
+
|
|
7
|
+
| Parameter | Type | Description | Allowed values / constraint |
|
|
8
|
+
|-----------|------|-------------|------------------------------|
|
|
9
|
+
| **feeRate** | number | Trading fee rate (%) | **Exactly one of**: `1`, `3`, `5`, `10` |
|
|
10
|
+
| **burnRate** | number | Burn share (%) | Custom; see constraints below |
|
|
11
|
+
| **divideRate** | number | Dividend share (%) | Custom; see below |
|
|
12
|
+
| **liquidityRate** | number | Liquidity share (%) | Custom; see below |
|
|
13
|
+
| **recipientRate** | number | Recipient share (%) | Custom; use `0` if not used |
|
|
14
|
+
| **recipientAddress** | string | Address that receives allocation | Use `""` if not used |
|
|
15
|
+
| **minSharing** | number | Min balance for dividends (ether units) | Must satisfy `d × 10ⁿ`, n≥5, 1≤d≤9 |
|
|
16
|
+
|
|
17
|
+
## Constraints
|
|
18
|
+
|
|
19
|
+
1. **feeRate** must be one of **1, 3, 5, 10** (1%, 3%, 5%, 10%).
|
|
20
|
+
2. **burnRate + divideRate + liquidityRate + recipientRate = 100** (the four shares must sum to 100).
|
|
21
|
+
3. If no recipient: **recipientAddress = ""** and **recipientRate = 0**.
|
|
22
|
+
4. **minSharing** examples: `100000` (1×10⁵), `200000`, `500000`, `1000000` (1×10⁶), `9000000`, `10000000` (1×10⁷), i.e. `d × 10ⁿ` with n≥5, 1≤d≤9.
|
|
23
|
+
|
|
24
|
+
## Examples
|
|
25
|
+
|
|
26
|
+
**Example 1: 5% fee, 20% burn, 30% dividend, 40% liquidity, 10% recipient**
|
|
27
|
+
|
|
28
|
+
```json
|
|
29
|
+
{
|
|
30
|
+
"tokenTaxInfo": {
|
|
31
|
+
"feeRate": 5,
|
|
32
|
+
"burnRate": 20,
|
|
33
|
+
"divideRate": 30,
|
|
34
|
+
"liquidityRate": 40,
|
|
35
|
+
"recipientRate": 10,
|
|
36
|
+
"recipientAddress": "0x1234567890123456789012345678901234567890",
|
|
37
|
+
"minSharing": 100000
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
**Example 2: 3% fee, 100% liquidity, no dividend/burn/recipient**
|
|
43
|
+
|
|
44
|
+
```json
|
|
45
|
+
{
|
|
46
|
+
"tokenTaxInfo": {
|
|
47
|
+
"feeRate": 3,
|
|
48
|
+
"burnRate": 0,
|
|
49
|
+
"divideRate": 0,
|
|
50
|
+
"liquidityRate": 100,
|
|
51
|
+
"recipientRate": 0,
|
|
52
|
+
"recipientAddress": "",
|
|
53
|
+
"minSharing": 100000
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
**Example 3: 10% fee, 50% dividend, 50% burn, min share 1×10⁶**
|
|
59
|
+
|
|
60
|
+
```json
|
|
61
|
+
{
|
|
62
|
+
"tokenTaxInfo": {
|
|
63
|
+
"feeRate": 10,
|
|
64
|
+
"burnRate": 50,
|
|
65
|
+
"divideRate": 50,
|
|
66
|
+
"liquidityRate": 0,
|
|
67
|
+
"recipientRate": 0,
|
|
68
|
+
"recipientAddress": "",
|
|
69
|
+
"minSharing": 1000000
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## Use in scripts
|
|
75
|
+
|
|
76
|
+
- **Option 1 (recommended)**: Write the above `tokenTaxInfo` to a JSON file (can contain only `tokenTaxInfo`) and pass that file path as the last argument to `create-token-api.ts`; the script merges it into the create body.
|
|
77
|
+
- **Option 2**: Build tax params via env vars (see “Create token (API)” optional env in SKILL.md).
|
|
@@ -1,52 +1,52 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
/**
|
|
3
|
-
* EIP-8004 NFT – query balance (number of identity NFTs owned by address).
|
|
4
|
-
*
|
|
5
|
-
* Usage:
|
|
6
|
-
* npx tsx 8004-balance.ts <ownerAddress>
|
|
7
|
-
*
|
|
8
|
-
* Optional env: BSC_RPC_URL, 8004_NFT_ADDRESS.
|
|
9
|
-
* Default contract: 0x8004A169FB4a3325136EB29fA0ceB6D2e539a432 (BSC).
|
|
10
|
-
*/
|
|
11
|
-
|
|
12
|
-
import { createPublicClient, http, parseAbi } from 'viem';
|
|
13
|
-
import { bsc } from 'viem/chains';
|
|
14
|
-
|
|
15
|
-
const DEFAULT_8004_NFT = '0x8004A169FB4a3325136EB29fA0ceB6D2e539a432' as const;
|
|
16
|
-
|
|
17
|
-
const ABI = parseAbi(['function balanceOf(address owner) view returns (uint256)']);
|
|
18
|
-
|
|
19
|
-
function isAddress(s: string): boolean {
|
|
20
|
-
return /^0x[0-9a-fA-F]{40}$/.test(s);
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
async function main() {
|
|
24
|
-
const ownerAddress = process.argv[2];
|
|
25
|
-
if (!ownerAddress || !isAddress(ownerAddress)) {
|
|
26
|
-
console.error('Usage: 8004-balance.ts <ownerAddress>');
|
|
27
|
-
console.error(' ownerAddress: 0x... wallet address');
|
|
28
|
-
process.exit(1);
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
const contractAddress = (process.env['8004_NFT_ADDRESS'] || process.env.EIP8004_NFT_ADDRESS || DEFAULT_8004_NFT) as `0x${string}`;
|
|
32
|
-
const rpcUrl = process.env.BSC_RPC_URL || 'https://bsc-dataseed.binance.org';
|
|
33
|
-
|
|
34
|
-
const client = createPublicClient({
|
|
35
|
-
chain: bsc,
|
|
36
|
-
transport: http(rpcUrl),
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
const balance = await client.readContract({
|
|
40
|
-
address: contractAddress,
|
|
41
|
-
abi: ABI,
|
|
42
|
-
functionName: 'balanceOf',
|
|
43
|
-
args: [ownerAddress as `0x${string}`],
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
console.log(JSON.stringify({ owner: ownerAddress, balance: Number(balance) }, null, 2));
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
main().catch((e) => {
|
|
50
|
-
console.error(e.message || e);
|
|
51
|
-
process.exit(1);
|
|
52
|
-
});
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* EIP-8004 NFT – query balance (number of identity NFTs owned by address).
|
|
4
|
+
*
|
|
5
|
+
* Usage:
|
|
6
|
+
* npx tsx 8004-balance.ts <ownerAddress>
|
|
7
|
+
*
|
|
8
|
+
* Optional env: BSC_RPC_URL, 8004_NFT_ADDRESS.
|
|
9
|
+
* Default contract: 0x8004A169FB4a3325136EB29fA0ceB6D2e539a432 (BSC).
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { createPublicClient, http, parseAbi } from 'viem';
|
|
13
|
+
import { bsc } from 'viem/chains';
|
|
14
|
+
|
|
15
|
+
const DEFAULT_8004_NFT = '0x8004A169FB4a3325136EB29fA0ceB6D2e539a432' as const;
|
|
16
|
+
|
|
17
|
+
const ABI = parseAbi(['function balanceOf(address owner) view returns (uint256)']);
|
|
18
|
+
|
|
19
|
+
function isAddress(s: string): boolean {
|
|
20
|
+
return /^0x[0-9a-fA-F]{40}$/.test(s);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
async function main() {
|
|
24
|
+
const ownerAddress = process.argv[2];
|
|
25
|
+
if (!ownerAddress || !isAddress(ownerAddress)) {
|
|
26
|
+
console.error('Usage: 8004-balance.ts <ownerAddress>');
|
|
27
|
+
console.error(' ownerAddress: 0x... wallet address');
|
|
28
|
+
process.exit(1);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const contractAddress = (process.env['8004_NFT_ADDRESS'] || process.env.EIP8004_NFT_ADDRESS || DEFAULT_8004_NFT) as `0x${string}`;
|
|
32
|
+
const rpcUrl = process.env.BSC_RPC_URL || 'https://bsc-dataseed.binance.org';
|
|
33
|
+
|
|
34
|
+
const client = createPublicClient({
|
|
35
|
+
chain: bsc,
|
|
36
|
+
transport: http(rpcUrl),
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
const balance = await client.readContract({
|
|
40
|
+
address: contractAddress,
|
|
41
|
+
abi: ABI,
|
|
42
|
+
functionName: 'balanceOf',
|
|
43
|
+
args: [ownerAddress as `0x${string}`],
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
console.log(JSON.stringify({ owner: ownerAddress, balance: Number(balance) }, null, 2));
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
main().catch((e) => {
|
|
50
|
+
console.error(e.message || e);
|
|
51
|
+
process.exit(1);
|
|
52
|
+
});
|
|
@@ -1,108 +1,108 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
/**
|
|
3
|
-
* EIP-8004 NFT – register agent (mint identity NFT).
|
|
4
|
-
* Builds agentURI as data:application/json;base64,<payload> and calls contract.register(agentURI).
|
|
5
|
-
*
|
|
6
|
-
* Usage:
|
|
7
|
-
* npx tsx 8004-register.ts <name> [imageUrl] [description]
|
|
8
|
-
* - name: required
|
|
9
|
-
* - imageUrl: optional (URL string)
|
|
10
|
-
* - description: optional
|
|
11
|
-
*
|
|
12
|
-
* Env: PRIVATE_KEY. Optional: BSC_RPC_URL, 8004_NFT_ADDRESS.
|
|
13
|
-
* Default contract: 0x8004A169FB4a3325136EB29fA0ceB6D2e539a432 (BSC).
|
|
14
|
-
*/
|
|
15
|
-
|
|
16
|
-
import { createPublicClient, createWalletClient, decodeEventLog, http, parseAbi } from 'viem';
|
|
17
|
-
import { privateKeyToAccount } from 'viem/accounts';
|
|
18
|
-
import { bsc } from 'viem/chains';
|
|
19
|
-
|
|
20
|
-
const DEFAULT_8004_NFT = '0x8004A169FB4a3325136EB29fA0ceB6D2e539a432' as const;
|
|
21
|
-
|
|
22
|
-
const REGISTRATION_TYPE = 'https://eips.ethereum.org/EIPS/eip-8004#registration-v1';
|
|
23
|
-
|
|
24
|
-
const ABI = parseAbi([
|
|
25
|
-
'function register(string agentURI) returns (uint256 agentId)',
|
|
26
|
-
'event Registered(uint256 indexed agentId, string agentURI, address indexed owner)',
|
|
27
|
-
]);
|
|
28
|
-
|
|
29
|
-
function buildAgentURI(name: string, imageUrl: string, description: string): string {
|
|
30
|
-
const payload = {
|
|
31
|
-
type: REGISTRATION_TYPE,
|
|
32
|
-
name: name || '',
|
|
33
|
-
description: description || 'I\'m four.meme trading agent',
|
|
34
|
-
image: imageUrl || '',
|
|
35
|
-
active: true,
|
|
36
|
-
supportedTrust: [''],
|
|
37
|
-
};
|
|
38
|
-
const json = JSON.stringify(payload);
|
|
39
|
-
const base64 = Buffer.from(json, 'utf8').toString('base64');
|
|
40
|
-
return `data:application/json;base64,${base64}`;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
async function main() {
|
|
44
|
-
const privateKey = process.env.PRIVATE_KEY;
|
|
45
|
-
if (!privateKey) {
|
|
46
|
-
console.error('Set PRIVATE_KEY');
|
|
47
|
-
process.exit(1);
|
|
48
|
-
}
|
|
49
|
-
const pk = privateKey.startsWith('0x') ? (privateKey as `0x${string}`) : (`0x${privateKey}` as `0x${string}`);
|
|
50
|
-
const account = privateKeyToAccount(pk);
|
|
51
|
-
|
|
52
|
-
const name = process.argv[2];
|
|
53
|
-
const imageUrl = process.argv[3] ?? '';
|
|
54
|
-
const description = process.argv[4] ?? '';
|
|
55
|
-
|
|
56
|
-
if (!name || name.trim() === '') {
|
|
57
|
-
console.error('Usage: 8004-register.ts <name> [imageUrl] [description]');
|
|
58
|
-
console.error(' name: required. imageUrl and description are optional.');
|
|
59
|
-
process.exit(1);
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
const agentURI = buildAgentURI(name.trim(), imageUrl.trim(), description.trim());
|
|
63
|
-
const contractAddress = (process.env['8004_NFT_ADDRESS'] || process.env.EIP8004_NFT_ADDRESS || DEFAULT_8004_NFT) as `0x${string}`;
|
|
64
|
-
const rpcUrl = process.env.BSC_RPC_URL || 'https://bsc-dataseed.binance.org';
|
|
65
|
-
|
|
66
|
-
const wallet = createWalletClient({
|
|
67
|
-
account,
|
|
68
|
-
chain: bsc,
|
|
69
|
-
transport: http(rpcUrl),
|
|
70
|
-
});
|
|
71
|
-
const publicClient = createPublicClient({
|
|
72
|
-
chain: bsc,
|
|
73
|
-
transport: http(rpcUrl),
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
const txHash = await wallet.writeContract({
|
|
77
|
-
address: contractAddress,
|
|
78
|
-
abi: ABI,
|
|
79
|
-
functionName: 'register',
|
|
80
|
-
args: [agentURI],
|
|
81
|
-
});
|
|
82
|
-
|
|
83
|
-
const receipt = await publicClient.waitForTransactionReceipt({ hash: txHash });
|
|
84
|
-
let agentId: number | null = null;
|
|
85
|
-
for (const l of receipt.logs) {
|
|
86
|
-
if (l.address.toLowerCase() !== contractAddress.toLowerCase()) continue;
|
|
87
|
-
try {
|
|
88
|
-
const d = decodeEventLog({
|
|
89
|
-
abi: ABI,
|
|
90
|
-
data: l.data,
|
|
91
|
-
topics: l.topics,
|
|
92
|
-
});
|
|
93
|
-
if (d.eventName === 'Registered') {
|
|
94
|
-
agentId = Number((d.args as { agentId: bigint }).agentId);
|
|
95
|
-
break;
|
|
96
|
-
}
|
|
97
|
-
} catch {
|
|
98
|
-
/* ignore */
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
console.log(JSON.stringify({ txHash, agentId, agentURI }, null, 2));
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
main().catch((e) => {
|
|
106
|
-
console.error(e.message || e);
|
|
107
|
-
process.exit(1);
|
|
108
|
-
});
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* EIP-8004 NFT – register agent (mint identity NFT).
|
|
4
|
+
* Builds agentURI as data:application/json;base64,<payload> and calls contract.register(agentURI).
|
|
5
|
+
*
|
|
6
|
+
* Usage:
|
|
7
|
+
* npx tsx 8004-register.ts <name> [imageUrl] [description]
|
|
8
|
+
* - name: required
|
|
9
|
+
* - imageUrl: optional (URL string)
|
|
10
|
+
* - description: optional
|
|
11
|
+
*
|
|
12
|
+
* Env: PRIVATE_KEY. Optional: BSC_RPC_URL, 8004_NFT_ADDRESS.
|
|
13
|
+
* Default contract: 0x8004A169FB4a3325136EB29fA0ceB6D2e539a432 (BSC).
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import { createPublicClient, createWalletClient, decodeEventLog, http, parseAbi } from 'viem';
|
|
17
|
+
import { privateKeyToAccount } from 'viem/accounts';
|
|
18
|
+
import { bsc } from 'viem/chains';
|
|
19
|
+
|
|
20
|
+
const DEFAULT_8004_NFT = '0x8004A169FB4a3325136EB29fA0ceB6D2e539a432' as const;
|
|
21
|
+
|
|
22
|
+
const REGISTRATION_TYPE = 'https://eips.ethereum.org/EIPS/eip-8004#registration-v1';
|
|
23
|
+
|
|
24
|
+
const ABI = parseAbi([
|
|
25
|
+
'function register(string agentURI) returns (uint256 agentId)',
|
|
26
|
+
'event Registered(uint256 indexed agentId, string agentURI, address indexed owner)',
|
|
27
|
+
]);
|
|
28
|
+
|
|
29
|
+
function buildAgentURI(name: string, imageUrl: string, description: string): string {
|
|
30
|
+
const payload = {
|
|
31
|
+
type: REGISTRATION_TYPE,
|
|
32
|
+
name: name || '',
|
|
33
|
+
description: description || 'I\'m four.meme trading agent',
|
|
34
|
+
image: imageUrl || '',
|
|
35
|
+
active: true,
|
|
36
|
+
supportedTrust: [''],
|
|
37
|
+
};
|
|
38
|
+
const json = JSON.stringify(payload);
|
|
39
|
+
const base64 = Buffer.from(json, 'utf8').toString('base64');
|
|
40
|
+
return `data:application/json;base64,${base64}`;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
async function main() {
|
|
44
|
+
const privateKey = process.env.PRIVATE_KEY;
|
|
45
|
+
if (!privateKey) {
|
|
46
|
+
console.error('Set PRIVATE_KEY');
|
|
47
|
+
process.exit(1);
|
|
48
|
+
}
|
|
49
|
+
const pk = privateKey.startsWith('0x') ? (privateKey as `0x${string}`) : (`0x${privateKey}` as `0x${string}`);
|
|
50
|
+
const account = privateKeyToAccount(pk);
|
|
51
|
+
|
|
52
|
+
const name = process.argv[2];
|
|
53
|
+
const imageUrl = process.argv[3] ?? '';
|
|
54
|
+
const description = process.argv[4] ?? '';
|
|
55
|
+
|
|
56
|
+
if (!name || name.trim() === '') {
|
|
57
|
+
console.error('Usage: 8004-register.ts <name> [imageUrl] [description]');
|
|
58
|
+
console.error(' name: required. imageUrl and description are optional.');
|
|
59
|
+
process.exit(1);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const agentURI = buildAgentURI(name.trim(), imageUrl.trim(), description.trim());
|
|
63
|
+
const contractAddress = (process.env['8004_NFT_ADDRESS'] || process.env.EIP8004_NFT_ADDRESS || DEFAULT_8004_NFT) as `0x${string}`;
|
|
64
|
+
const rpcUrl = process.env.BSC_RPC_URL || 'https://bsc-dataseed.binance.org';
|
|
65
|
+
|
|
66
|
+
const wallet = createWalletClient({
|
|
67
|
+
account,
|
|
68
|
+
chain: bsc,
|
|
69
|
+
transport: http(rpcUrl),
|
|
70
|
+
});
|
|
71
|
+
const publicClient = createPublicClient({
|
|
72
|
+
chain: bsc,
|
|
73
|
+
transport: http(rpcUrl),
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
const txHash = await wallet.writeContract({
|
|
77
|
+
address: contractAddress,
|
|
78
|
+
abi: ABI,
|
|
79
|
+
functionName: 'register',
|
|
80
|
+
args: [agentURI],
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
const receipt = await publicClient.waitForTransactionReceipt({ hash: txHash });
|
|
84
|
+
let agentId: number | null = null;
|
|
85
|
+
for (const l of receipt.logs) {
|
|
86
|
+
if (l.address.toLowerCase() !== contractAddress.toLowerCase()) continue;
|
|
87
|
+
try {
|
|
88
|
+
const d = decodeEventLog({
|
|
89
|
+
abi: ABI,
|
|
90
|
+
data: l.data,
|
|
91
|
+
topics: l.topics,
|
|
92
|
+
});
|
|
93
|
+
if (d.eventName === 'Registered') {
|
|
94
|
+
agentId = Number((d.args as { agentId: bigint }).agentId);
|
|
95
|
+
break;
|
|
96
|
+
}
|
|
97
|
+
} catch {
|
|
98
|
+
/* ignore */
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
console.log(JSON.stringify({ txHash, agentId, agentURI }, null, 2));
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
main().catch((e) => {
|
|
106
|
+
console.error(e.message || e);
|
|
107
|
+
process.exit(1);
|
|
108
|
+
});
|