@paylobster/cli 4.0.0
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/BUILD_SUMMARY.md +429 -0
- package/CHANGELOG.md +78 -0
- package/CONTRIBUTING.md +368 -0
- package/EXAMPLES.md +432 -0
- package/LICENSE +21 -0
- package/QUICKSTART.md +189 -0
- package/README.md +377 -0
- package/TEST_REPORT.md +191 -0
- package/bin/plob.js +9 -0
- package/bin/plob.ts +9 -0
- package/demo.sh +154 -0
- package/dist/bin/plob.d.ts +7 -0
- package/dist/bin/plob.d.ts.map +1 -0
- package/dist/bin/plob.js +10 -0
- package/dist/bin/plob.js.map +1 -0
- package/dist/src/commands/auth.d.ts +3 -0
- package/dist/src/commands/auth.d.ts.map +1 -0
- package/dist/src/commands/auth.js +75 -0
- package/dist/src/commands/auth.js.map +1 -0
- package/dist/src/commands/config.d.ts +3 -0
- package/dist/src/commands/config.d.ts.map +1 -0
- package/dist/src/commands/config.js +79 -0
- package/dist/src/commands/config.js.map +1 -0
- package/dist/src/commands/escrow.d.ts +3 -0
- package/dist/src/commands/escrow.d.ts.map +1 -0
- package/dist/src/commands/escrow.js +193 -0
- package/dist/src/commands/escrow.js.map +1 -0
- package/dist/src/commands/mandate.d.ts +8 -0
- package/dist/src/commands/mandate.d.ts.map +1 -0
- package/dist/src/commands/mandate.js +54 -0
- package/dist/src/commands/mandate.js.map +1 -0
- package/dist/src/commands/pay.d.ts +6 -0
- package/dist/src/commands/pay.d.ts.map +1 -0
- package/dist/src/commands/pay.js +77 -0
- package/dist/src/commands/pay.js.map +1 -0
- package/dist/src/commands/register.d.ts +3 -0
- package/dist/src/commands/register.d.ts.map +1 -0
- package/dist/src/commands/register.js +51 -0
- package/dist/src/commands/register.js.map +1 -0
- package/dist/src/commands/reputation.d.ts +3 -0
- package/dist/src/commands/reputation.d.ts.map +1 -0
- package/dist/src/commands/reputation.js +116 -0
- package/dist/src/commands/reputation.js.map +1 -0
- package/dist/src/commands/status.d.ts +3 -0
- package/dist/src/commands/status.d.ts.map +1 -0
- package/dist/src/commands/status.js +82 -0
- package/dist/src/commands/status.js.map +1 -0
- package/dist/src/index.d.ts +3 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +59 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/lib/config.d.ts +26 -0
- package/dist/src/lib/config.d.ts.map +1 -0
- package/dist/src/lib/config.js +91 -0
- package/dist/src/lib/config.js.map +1 -0
- package/dist/src/lib/contracts.d.ts +18798 -0
- package/dist/src/lib/contracts.d.ts.map +1 -0
- package/dist/src/lib/contracts.js +361 -0
- package/dist/src/lib/contracts.js.map +1 -0
- package/dist/src/lib/display.d.ts +83 -0
- package/dist/src/lib/display.d.ts.map +1 -0
- package/dist/src/lib/display.js +293 -0
- package/dist/src/lib/display.js.map +1 -0
- package/dist/src/lib/types.d.ts +49 -0
- package/dist/src/lib/types.d.ts.map +1 -0
- package/dist/src/lib/types.js +3 -0
- package/dist/src/lib/types.js.map +1 -0
- package/dist/src/lib/wallet.d.ts +30 -0
- package/dist/src/lib/wallet.d.ts.map +1 -0
- package/dist/src/lib/wallet.js +143 -0
- package/dist/src/lib/wallet.js.map +1 -0
- package/jest.config.js +15 -0
- package/package.json +55 -0
- package/src/__tests__/cli.test.ts +38 -0
- package/src/commands/auth.ts +75 -0
- package/src/commands/config.ts +84 -0
- package/src/commands/escrow.ts +222 -0
- package/src/commands/mandate.ts +56 -0
- package/src/commands/pay.ts +96 -0
- package/src/commands/register.ts +57 -0
- package/src/commands/reputation.ts +84 -0
- package/src/commands/status.ts +91 -0
- package/src/index.ts +63 -0
- package/src/lib/config.ts +90 -0
- package/src/lib/contracts.ts +392 -0
- package/src/lib/display.ts +265 -0
- package/src/lib/types.ts +57 -0
- package/src/lib/wallet.ts +146 -0
- package/tsconfig.json +21 -0
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import { getAgentInfo, getReputation, getCreditStatus, getBalance, getUserEscrowCount, formatUSDC, formatETH } from '../lib/contracts';
|
|
3
|
+
import { getWalletAddress } from '../lib/wallet';
|
|
4
|
+
import { loadConfig } from '../lib/config';
|
|
5
|
+
import { error, outputJSON, printAgentHeader, formatBoolean, formatNumber, printReputation, formatNetwork } from '../lib/display';
|
|
6
|
+
import type { OutputOptions } from '../lib/types';
|
|
7
|
+
|
|
8
|
+
export function createStatusCommand(): Command {
|
|
9
|
+
const cmd = new Command('status')
|
|
10
|
+
.description('Show agent status and balances')
|
|
11
|
+
.option('--json', 'Output as JSON')
|
|
12
|
+
.action(async (options: OutputOptions) => {
|
|
13
|
+
try {
|
|
14
|
+
const address = getWalletAddress() as `0x${string}`;
|
|
15
|
+
const config = loadConfig();
|
|
16
|
+
|
|
17
|
+
// Fetch all data in parallel
|
|
18
|
+
const [agentInfo, reputation, creditStatus, balance, escrowCount] = await Promise.all([
|
|
19
|
+
getAgentInfo(address),
|
|
20
|
+
getReputation(address),
|
|
21
|
+
getCreditStatus(address),
|
|
22
|
+
getBalance(address),
|
|
23
|
+
getUserEscrowCount(address),
|
|
24
|
+
]);
|
|
25
|
+
|
|
26
|
+
// Calculate reputation score (0-100)
|
|
27
|
+
const reputationScore = Number(reputation.score);
|
|
28
|
+
|
|
29
|
+
// Format balances
|
|
30
|
+
const usdcBalance = formatUSDC(balance.usdc);
|
|
31
|
+
const ethBalance = formatETH(balance.eth);
|
|
32
|
+
|
|
33
|
+
// Format credit
|
|
34
|
+
const creditLimit = formatUSDC(creditStatus.limit);
|
|
35
|
+
const creditAvailable = formatUSDC(creditStatus.available);
|
|
36
|
+
const creditInUse = formatUSDC(creditStatus.inUse);
|
|
37
|
+
|
|
38
|
+
if (outputJSON({
|
|
39
|
+
name: agentInfo.name,
|
|
40
|
+
address,
|
|
41
|
+
network: config.network,
|
|
42
|
+
registered: agentInfo.registered,
|
|
43
|
+
tokenId: agentInfo.tokenId.toString(),
|
|
44
|
+
balance: {
|
|
45
|
+
usdc: usdcBalance,
|
|
46
|
+
eth: ethBalance,
|
|
47
|
+
},
|
|
48
|
+
credit: {
|
|
49
|
+
limit: creditLimit,
|
|
50
|
+
available: creditAvailable,
|
|
51
|
+
inUse: creditInUse,
|
|
52
|
+
},
|
|
53
|
+
reputation: reputationScore,
|
|
54
|
+
escrows: escrowCount,
|
|
55
|
+
}, options)) {
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Pretty output
|
|
60
|
+
printAgentHeader(agentInfo.name || 'Not Registered', address);
|
|
61
|
+
|
|
62
|
+
console.log('Network: ', formatNetwork(config.network));
|
|
63
|
+
console.log('Registered: ', formatBoolean(agentInfo.registered));
|
|
64
|
+
|
|
65
|
+
if (agentInfo.registered) {
|
|
66
|
+
console.log('Agent ID: ', agentInfo.tokenId.toString());
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
console.log();
|
|
70
|
+
console.log('💰 Balances');
|
|
71
|
+
console.log(' USDC: ', formatNumber(usdcBalance), 'USDC');
|
|
72
|
+
console.log(' ETH: ', formatNumber(ethBalance), 'ETH');
|
|
73
|
+
|
|
74
|
+
console.log();
|
|
75
|
+
console.log('💳 Credit');
|
|
76
|
+
console.log(' Limit: ', formatNumber(creditLimit), 'USDC');
|
|
77
|
+
console.log(' Available:', formatNumber(creditAvailable), 'USDC');
|
|
78
|
+
console.log(' In Use: ', formatNumber(creditInUse), 'USDC');
|
|
79
|
+
|
|
80
|
+
console.log();
|
|
81
|
+
console.log('⭐ Reputation:', printReputation(reputationScore));
|
|
82
|
+
console.log('📦 Escrows: ', escrowCount, 'total');
|
|
83
|
+
console.log();
|
|
84
|
+
} catch (err) {
|
|
85
|
+
error(`Failed to fetch status: ${err}`);
|
|
86
|
+
process.exit(1);
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
return cmd;
|
|
91
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { Command } from 'commander';
|
|
4
|
+
import { createAuthCommand } from './commands/auth';
|
|
5
|
+
import { createConfigCommand } from './commands/config';
|
|
6
|
+
import { createRegisterCommand } from './commands/register';
|
|
7
|
+
import { createStatusCommand } from './commands/status';
|
|
8
|
+
import { createEscrowCommand } from './commands/escrow';
|
|
9
|
+
import { createMandateCommand } from './commands/mandate';
|
|
10
|
+
import { createPayCommand } from './commands/pay';
|
|
11
|
+
import { createReputationCommand } from './commands/reputation';
|
|
12
|
+
import chalk from 'chalk';
|
|
13
|
+
|
|
14
|
+
// Load environment variables from .env file if present
|
|
15
|
+
import dotenv from 'dotenv';
|
|
16
|
+
dotenv.config();
|
|
17
|
+
|
|
18
|
+
const program = new Command();
|
|
19
|
+
|
|
20
|
+
program
|
|
21
|
+
.name('plob')
|
|
22
|
+
.description('🦞 PayLobster CLI - Payment infrastructure for AI agents')
|
|
23
|
+
.version('4.0.0');
|
|
24
|
+
|
|
25
|
+
// ASCII art banner
|
|
26
|
+
const banner = `
|
|
27
|
+
${chalk.cyan('┌─────────────────────────────────┐')}
|
|
28
|
+
${chalk.cyan('│')} ${chalk.bold.cyan('🦞 PayLobster CLI')} ${chalk.cyan('│')}
|
|
29
|
+
${chalk.cyan('│')} Payment infrastructure for AI ${chalk.cyan('│')}
|
|
30
|
+
${chalk.cyan('└─────────────────────────────────┘')}
|
|
31
|
+
`;
|
|
32
|
+
|
|
33
|
+
// Show banner on help
|
|
34
|
+
program.on('--help', () => {
|
|
35
|
+
console.log(banner);
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
// Add commands
|
|
39
|
+
program.addCommand(createAuthCommand());
|
|
40
|
+
program.addCommand(createConfigCommand());
|
|
41
|
+
program.addCommand(createRegisterCommand());
|
|
42
|
+
program.addCommand(createStatusCommand());
|
|
43
|
+
program.addCommand(createEscrowCommand());
|
|
44
|
+
program.addCommand(createMandateCommand());
|
|
45
|
+
program.addCommand(createPayCommand());
|
|
46
|
+
program.addCommand(createReputationCommand());
|
|
47
|
+
|
|
48
|
+
// Handle errors
|
|
49
|
+
program.exitOverride((err) => {
|
|
50
|
+
if (err.code === 'commander.help') {
|
|
51
|
+
console.log(banner);
|
|
52
|
+
}
|
|
53
|
+
process.exit(err.exitCode);
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
// Parse arguments
|
|
57
|
+
program.parse(process.argv);
|
|
58
|
+
|
|
59
|
+
// Show help if no command provided
|
|
60
|
+
if (!process.argv.slice(2).length) {
|
|
61
|
+
console.log(banner);
|
|
62
|
+
program.outputHelp();
|
|
63
|
+
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import os from 'os';
|
|
4
|
+
import type { CLIConfig, Network } from './types';
|
|
5
|
+
|
|
6
|
+
const CONFIG_DIR = path.join(os.homedir(), '.plob');
|
|
7
|
+
const CONFIG_FILE = path.join(CONFIG_DIR, 'config.json');
|
|
8
|
+
|
|
9
|
+
// Default configuration
|
|
10
|
+
const DEFAULT_CONFIG: CLIConfig = {
|
|
11
|
+
network: 'sepolia',
|
|
12
|
+
indexerUrl: 'https://api.thegraph.com/subgraphs/name/paylobster/registry',
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Load CLI configuration from ~/.plob/config.json
|
|
17
|
+
*/
|
|
18
|
+
export function loadConfig(): CLIConfig {
|
|
19
|
+
try {
|
|
20
|
+
if (!fs.existsSync(CONFIG_FILE)) {
|
|
21
|
+
return DEFAULT_CONFIG;
|
|
22
|
+
}
|
|
23
|
+
const data = fs.readFileSync(CONFIG_FILE, 'utf-8');
|
|
24
|
+
return { ...DEFAULT_CONFIG, ...JSON.parse(data) };
|
|
25
|
+
} catch (error) {
|
|
26
|
+
return DEFAULT_CONFIG;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Save CLI configuration to ~/.plob/config.json
|
|
32
|
+
*/
|
|
33
|
+
export function saveConfig(config: Partial<CLIConfig>): void {
|
|
34
|
+
try {
|
|
35
|
+
// Ensure config directory exists
|
|
36
|
+
if (!fs.existsSync(CONFIG_DIR)) {
|
|
37
|
+
fs.mkdirSync(CONFIG_DIR, { recursive: true });
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const currentConfig = loadConfig();
|
|
41
|
+
const newConfig = { ...currentConfig, ...config };
|
|
42
|
+
|
|
43
|
+
fs.writeFileSync(CONFIG_FILE, JSON.stringify(newConfig, null, 2));
|
|
44
|
+
} catch (error) {
|
|
45
|
+
throw new Error(`Failed to save config: ${error}`);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Get a specific config value
|
|
51
|
+
*/
|
|
52
|
+
export function getConfigValue(key: keyof CLIConfig): any {
|
|
53
|
+
const config = loadConfig();
|
|
54
|
+
return config[key];
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Set a specific config value
|
|
59
|
+
*/
|
|
60
|
+
export function setConfigValue(key: keyof CLIConfig, value: any): void {
|
|
61
|
+
const config = loadConfig();
|
|
62
|
+
(config as any)[key] = value;
|
|
63
|
+
saveConfig(config);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Get RPC URL for the configured network
|
|
68
|
+
*/
|
|
69
|
+
export function getRpcUrl(network?: Network): string {
|
|
70
|
+
const config = loadConfig();
|
|
71
|
+
const net = network || config.network;
|
|
72
|
+
|
|
73
|
+
if (config.rpcUrl) {
|
|
74
|
+
return config.rpcUrl;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Default public RPCs
|
|
78
|
+
return net === 'mainnet'
|
|
79
|
+
? 'https://mainnet.base.org'
|
|
80
|
+
: 'https://sepolia.base.org';
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Clear all configuration
|
|
85
|
+
*/
|
|
86
|
+
export function clearConfig(): void {
|
|
87
|
+
if (fs.existsSync(CONFIG_FILE)) {
|
|
88
|
+
fs.unlinkSync(CONFIG_FILE);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
@@ -0,0 +1,392 @@
|
|
|
1
|
+
import { createPublicClient, http, type Address, formatUnits, parseUnits } from 'viem';
|
|
2
|
+
import { base, baseSepolia } from 'viem/chains';
|
|
3
|
+
import { loadWallet } from './wallet';
|
|
4
|
+
import { loadConfig, getRpcUrl } from './config';
|
|
5
|
+
import type { Network, AgentInfo, Reputation, CreditStatus, EscrowInfo, Balance } from './types';
|
|
6
|
+
|
|
7
|
+
// Contract addresses
|
|
8
|
+
const CONTRACTS_MAINNET = {
|
|
9
|
+
IDENTITY: '0xA174ee274F870631B3c330a85EBCad74120BE662' as Address,
|
|
10
|
+
REPUTATION: '0x02bb4132a86134684976E2a52E43D59D89E64b29' as Address,
|
|
11
|
+
CREDIT: '0xD9241Ce8a721Ef5fcCAc5A11983addC526eC80E1' as Address,
|
|
12
|
+
ESCROW: '0x49EdEe04c78B7FeD5248A20706c7a6c540748806' as Address,
|
|
13
|
+
USDC: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913' as Address,
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
const CONTRACTS_SEPOLIA = {
|
|
17
|
+
IDENTITY: '0x3dfA02Ed4F0e4F10E8031d7a4cB8Ea0bBbFbCB8c' as Address,
|
|
18
|
+
// NOTE: Reputation address provided has 41 hex chars (invalid). Using placeholder.
|
|
19
|
+
// Original (invalid): 0xb0033901e3b94f4F36dA0b3e396942C1e78205C7d
|
|
20
|
+
REPUTATION: '0x0000000000000000000000000000000000000000' as Address, // TODO: Fix this address
|
|
21
|
+
CREDIT: '0xBA64e2b2F2a80D03A4B13b3396942C1e78205C7d' as Address,
|
|
22
|
+
ESCROW: '0x78D1f50a1965dE34f6b5a3D3546C94FE1809Cd82' as Address,
|
|
23
|
+
USDC: '0x036CbD53842c5426634e7929541eC2318f3dCF7e' as Address,
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
// ABIs
|
|
27
|
+
const IDENTITY_ABI = [
|
|
28
|
+
{
|
|
29
|
+
inputs: [
|
|
30
|
+
{ name: 'agentURI', type: 'string' },
|
|
31
|
+
{ name: 'name', type: 'string' },
|
|
32
|
+
{ name: 'capabilities', type: 'string' },
|
|
33
|
+
],
|
|
34
|
+
name: 'register',
|
|
35
|
+
outputs: [{ name: 'agentId', type: 'uint256' }],
|
|
36
|
+
stateMutability: 'nonpayable',
|
|
37
|
+
type: 'function',
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
inputs: [{ name: 'user', type: 'address' }],
|
|
41
|
+
name: 'getAgentInfo',
|
|
42
|
+
outputs: [
|
|
43
|
+
{ name: 'name', type: 'string' },
|
|
44
|
+
{ name: 'tokenId', type: 'uint256' },
|
|
45
|
+
{ name: 'registered', type: 'bool' },
|
|
46
|
+
],
|
|
47
|
+
stateMutability: 'view',
|
|
48
|
+
type: 'function',
|
|
49
|
+
},
|
|
50
|
+
] as const;
|
|
51
|
+
|
|
52
|
+
const REPUTATION_ABI = [
|
|
53
|
+
{
|
|
54
|
+
inputs: [{ name: 'user', type: 'address' }],
|
|
55
|
+
name: 'getReputation',
|
|
56
|
+
outputs: [
|
|
57
|
+
{ name: 'score', type: 'uint256' },
|
|
58
|
+
{ name: 'trustVector', type: 'uint256' },
|
|
59
|
+
],
|
|
60
|
+
stateMutability: 'view',
|
|
61
|
+
type: 'function',
|
|
62
|
+
},
|
|
63
|
+
] as const;
|
|
64
|
+
|
|
65
|
+
const CREDIT_ABI = [
|
|
66
|
+
{
|
|
67
|
+
inputs: [{ name: 'user', type: 'address' }],
|
|
68
|
+
name: 'getCreditStatus',
|
|
69
|
+
outputs: [
|
|
70
|
+
{ name: 'limit', type: 'uint256' },
|
|
71
|
+
{ name: 'available', type: 'uint256' },
|
|
72
|
+
{ name: 'inUse', type: 'uint256' },
|
|
73
|
+
],
|
|
74
|
+
stateMutability: 'view',
|
|
75
|
+
type: 'function',
|
|
76
|
+
},
|
|
77
|
+
] as const;
|
|
78
|
+
|
|
79
|
+
const ESCROW_ABI = [
|
|
80
|
+
{
|
|
81
|
+
inputs: [
|
|
82
|
+
{ name: 'recipient', type: 'address' },
|
|
83
|
+
{ name: 'amount', type: 'uint256' },
|
|
84
|
+
{ name: 'token', type: 'address' },
|
|
85
|
+
{ name: 'description', type: 'string' },
|
|
86
|
+
],
|
|
87
|
+
name: 'createEscrow',
|
|
88
|
+
outputs: [{ name: 'escrowId', type: 'uint256' }],
|
|
89
|
+
stateMutability: 'nonpayable',
|
|
90
|
+
type: 'function',
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
inputs: [{ name: 'escrowId', type: 'uint256' }],
|
|
94
|
+
name: 'releaseEscrow',
|
|
95
|
+
outputs: [],
|
|
96
|
+
stateMutability: 'nonpayable',
|
|
97
|
+
type: 'function',
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
inputs: [{ name: 'escrowId', type: 'uint256' }],
|
|
101
|
+
name: 'getEscrow',
|
|
102
|
+
outputs: [
|
|
103
|
+
{ name: 'sender', type: 'address' },
|
|
104
|
+
{ name: 'recipient', type: 'address' },
|
|
105
|
+
{ name: 'amount', type: 'uint256' },
|
|
106
|
+
{ name: 'token', type: 'address' },
|
|
107
|
+
{ name: 'status', type: 'uint8' },
|
|
108
|
+
],
|
|
109
|
+
stateMutability: 'view',
|
|
110
|
+
type: 'function',
|
|
111
|
+
},
|
|
112
|
+
] as const;
|
|
113
|
+
|
|
114
|
+
const USDC_ABI = [
|
|
115
|
+
{
|
|
116
|
+
inputs: [
|
|
117
|
+
{ name: 'spender', type: 'address' },
|
|
118
|
+
{ name: 'amount', type: 'uint256' },
|
|
119
|
+
],
|
|
120
|
+
name: 'approve',
|
|
121
|
+
outputs: [{ name: '', type: 'bool' }],
|
|
122
|
+
stateMutability: 'nonpayable',
|
|
123
|
+
type: 'function',
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
inputs: [{ name: 'account', type: 'address' }],
|
|
127
|
+
name: 'balanceOf',
|
|
128
|
+
outputs: [{ name: '', type: 'uint256' }],
|
|
129
|
+
stateMutability: 'view',
|
|
130
|
+
type: 'function',
|
|
131
|
+
},
|
|
132
|
+
] as const;
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Get contract addresses for network
|
|
136
|
+
*/
|
|
137
|
+
export function getContracts(network: Network) {
|
|
138
|
+
return network === 'mainnet' ? CONTRACTS_MAINNET : CONTRACTS_SEPOLIA;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Create public client for reading
|
|
143
|
+
*/
|
|
144
|
+
export function getPublicClient(network?: Network) {
|
|
145
|
+
const config = loadConfig();
|
|
146
|
+
const net = network || config.network;
|
|
147
|
+
const chain = net === 'mainnet' ? base : baseSepolia;
|
|
148
|
+
|
|
149
|
+
return createPublicClient({
|
|
150
|
+
chain,
|
|
151
|
+
transport: http(getRpcUrl(net)),
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Register agent identity
|
|
157
|
+
*/
|
|
158
|
+
export async function registerAgent(name: string, capabilities: string): Promise<bigint> {
|
|
159
|
+
const { client, account } = await loadWallet();
|
|
160
|
+
const config = loadConfig();
|
|
161
|
+
const contracts = getContracts(config.network);
|
|
162
|
+
const chain = config.network === 'mainnet' ? base : baseSepolia;
|
|
163
|
+
|
|
164
|
+
const hash = await client.writeContract({
|
|
165
|
+
address: contracts.IDENTITY,
|
|
166
|
+
abi: IDENTITY_ABI,
|
|
167
|
+
functionName: 'register',
|
|
168
|
+
args: ['', name, capabilities],
|
|
169
|
+
account,
|
|
170
|
+
chain,
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
return BigInt(hash);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Get agent info
|
|
178
|
+
*/
|
|
179
|
+
export async function getAgentInfo(address: Address): Promise<AgentInfo> {
|
|
180
|
+
const config = loadConfig();
|
|
181
|
+
const publicClient = getPublicClient(config.network);
|
|
182
|
+
const contracts = getContracts(config.network);
|
|
183
|
+
|
|
184
|
+
const result = await publicClient.readContract({
|
|
185
|
+
address: contracts.IDENTITY,
|
|
186
|
+
abi: IDENTITY_ABI,
|
|
187
|
+
functionName: 'getAgentInfo',
|
|
188
|
+
args: [address],
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
return {
|
|
192
|
+
name: result[0],
|
|
193
|
+
tokenId: result[1],
|
|
194
|
+
registered: result[2],
|
|
195
|
+
address,
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* Get reputation score
|
|
201
|
+
*/
|
|
202
|
+
export async function getReputation(address: Address): Promise<Reputation> {
|
|
203
|
+
const config = loadConfig();
|
|
204
|
+
const publicClient = getPublicClient(config.network);
|
|
205
|
+
const contracts = getContracts(config.network);
|
|
206
|
+
|
|
207
|
+
const result = await publicClient.readContract({
|
|
208
|
+
address: contracts.REPUTATION,
|
|
209
|
+
abi: REPUTATION_ABI,
|
|
210
|
+
functionName: 'getReputation',
|
|
211
|
+
args: [address],
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
return {
|
|
215
|
+
score: result[0],
|
|
216
|
+
trustVector: result[1],
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* Get credit status
|
|
222
|
+
*/
|
|
223
|
+
export async function getCreditStatus(address: Address): Promise<CreditStatus> {
|
|
224
|
+
const config = loadConfig();
|
|
225
|
+
const publicClient = getPublicClient(config.network);
|
|
226
|
+
const contracts = getContracts(config.network);
|
|
227
|
+
|
|
228
|
+
const result = await publicClient.readContract({
|
|
229
|
+
address: contracts.CREDIT,
|
|
230
|
+
abi: CREDIT_ABI,
|
|
231
|
+
functionName: 'getCreditStatus',
|
|
232
|
+
args: [address],
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
return {
|
|
236
|
+
limit: result[0],
|
|
237
|
+
available: result[1],
|
|
238
|
+
inUse: result[2],
|
|
239
|
+
};
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* Get USDC balance
|
|
244
|
+
*/
|
|
245
|
+
export async function getUSDCBalance(address: Address): Promise<bigint> {
|
|
246
|
+
const config = loadConfig();
|
|
247
|
+
const publicClient = getPublicClient(config.network);
|
|
248
|
+
const contracts = getContracts(config.network);
|
|
249
|
+
|
|
250
|
+
const balance = await publicClient.readContract({
|
|
251
|
+
address: contracts.USDC,
|
|
252
|
+
abi: USDC_ABI,
|
|
253
|
+
functionName: 'balanceOf',
|
|
254
|
+
args: [address],
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
return balance;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
/**
|
|
261
|
+
* Get ETH balance
|
|
262
|
+
*/
|
|
263
|
+
export async function getETHBalance(address: Address): Promise<bigint> {
|
|
264
|
+
const config = loadConfig();
|
|
265
|
+
const publicClient = getPublicClient(config.network);
|
|
266
|
+
|
|
267
|
+
const balance = await publicClient.getBalance({ address });
|
|
268
|
+
return balance;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
/**
|
|
272
|
+
* Get full balance info
|
|
273
|
+
*/
|
|
274
|
+
export async function getBalance(address: Address): Promise<Balance> {
|
|
275
|
+
const [usdc, eth] = await Promise.all([
|
|
276
|
+
getUSDCBalance(address),
|
|
277
|
+
getETHBalance(address),
|
|
278
|
+
]);
|
|
279
|
+
|
|
280
|
+
return { usdc, eth };
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
/**
|
|
284
|
+
* Create escrow
|
|
285
|
+
*/
|
|
286
|
+
export async function createEscrow(
|
|
287
|
+
recipient: Address,
|
|
288
|
+
amount: string,
|
|
289
|
+
description: string
|
|
290
|
+
): Promise<bigint> {
|
|
291
|
+
const { client, account } = await loadWallet();
|
|
292
|
+
const config = loadConfig();
|
|
293
|
+
const contracts = getContracts(config.network);
|
|
294
|
+
const chain = config.network === 'mainnet' ? base : baseSepolia;
|
|
295
|
+
|
|
296
|
+
// Parse amount (USDC has 6 decimals)
|
|
297
|
+
const amountWei = parseUnits(amount, 6);
|
|
298
|
+
|
|
299
|
+
// First approve USDC
|
|
300
|
+
const approveHash = await client.writeContract({
|
|
301
|
+
address: contracts.USDC,
|
|
302
|
+
abi: USDC_ABI,
|
|
303
|
+
functionName: 'approve',
|
|
304
|
+
args: [contracts.ESCROW, amountWei],
|
|
305
|
+
account,
|
|
306
|
+
chain,
|
|
307
|
+
});
|
|
308
|
+
|
|
309
|
+
// Wait for approval
|
|
310
|
+
const publicClient = getPublicClient(config.network);
|
|
311
|
+
await publicClient.waitForTransactionReceipt({ hash: approveHash });
|
|
312
|
+
|
|
313
|
+
// Create escrow
|
|
314
|
+
const hash = await client.writeContract({
|
|
315
|
+
address: contracts.ESCROW,
|
|
316
|
+
abi: ESCROW_ABI,
|
|
317
|
+
functionName: 'createEscrow',
|
|
318
|
+
args: [recipient, amountWei, contracts.USDC, description],
|
|
319
|
+
account,
|
|
320
|
+
chain,
|
|
321
|
+
});
|
|
322
|
+
|
|
323
|
+
return BigInt(hash);
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
/**
|
|
327
|
+
* Release escrow
|
|
328
|
+
*/
|
|
329
|
+
export async function releaseEscrow(escrowId: bigint): Promise<string> {
|
|
330
|
+
const { client, account } = await loadWallet();
|
|
331
|
+
const config = loadConfig();
|
|
332
|
+
const contracts = getContracts(config.network);
|
|
333
|
+
const chain = config.network === 'mainnet' ? base : baseSepolia;
|
|
334
|
+
|
|
335
|
+
const hash = await client.writeContract({
|
|
336
|
+
address: contracts.ESCROW,
|
|
337
|
+
abi: ESCROW_ABI,
|
|
338
|
+
functionName: 'releaseEscrow',
|
|
339
|
+
args: [escrowId],
|
|
340
|
+
account,
|
|
341
|
+
chain,
|
|
342
|
+
});
|
|
343
|
+
|
|
344
|
+
return hash;
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
/**
|
|
348
|
+
* Get escrow details
|
|
349
|
+
*/
|
|
350
|
+
export async function getEscrow(escrowId: bigint): Promise<EscrowInfo> {
|
|
351
|
+
const config = loadConfig();
|
|
352
|
+
const publicClient = getPublicClient(config.network);
|
|
353
|
+
const contracts = getContracts(config.network);
|
|
354
|
+
|
|
355
|
+
const result = await publicClient.readContract({
|
|
356
|
+
address: contracts.ESCROW,
|
|
357
|
+
abi: ESCROW_ABI,
|
|
358
|
+
functionName: 'getEscrow',
|
|
359
|
+
args: [escrowId],
|
|
360
|
+
});
|
|
361
|
+
|
|
362
|
+
return {
|
|
363
|
+
sender: result[0],
|
|
364
|
+
recipient: result[1],
|
|
365
|
+
amount: result[2],
|
|
366
|
+
token: result[3],
|
|
367
|
+
status: result[4],
|
|
368
|
+
};
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
/**
|
|
372
|
+
* Get user's escrow count
|
|
373
|
+
* NOTE: This function is not yet implemented on the deployed contract
|
|
374
|
+
*/
|
|
375
|
+
export async function getUserEscrowCount(address: Address): Promise<number> {
|
|
376
|
+
// TODO: Implement when Escrow V3 is deployed with getUserTransactionCount
|
|
377
|
+
return 0;
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
/**
|
|
381
|
+
* Format USDC amount for display
|
|
382
|
+
*/
|
|
383
|
+
export function formatUSDC(amount: bigint): string {
|
|
384
|
+
return formatUnits(amount, 6);
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
/**
|
|
388
|
+
* Format ETH amount for display
|
|
389
|
+
*/
|
|
390
|
+
export function formatETH(amount: bigint): string {
|
|
391
|
+
return formatUnits(amount, 18);
|
|
392
|
+
}
|