@zakyirsyaad/monagent-plugin 0.1.0 → 0.1.2
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/dist/commands/monad/identity/get.d.ts +19 -0
- package/dist/commands/monad/identity/get.js +113 -0
- package/dist/commands/monad/identity/register.d.ts +16 -0
- package/dist/commands/monad/identity/register.js +122 -0
- package/dist/commands/monad/jobs/complete.d.ts +15 -0
- package/dist/commands/monad/jobs/complete.js +63 -0
- package/dist/commands/{jobs → monad/jobs}/create.d.ts +5 -2
- package/dist/commands/monad/jobs/create.js +88 -0
- package/dist/commands/monad/jobs/refund.d.ts +14 -0
- package/dist/commands/monad/jobs/refund.js +56 -0
- package/dist/commands/{pay.d.ts → monad/pay.d.ts} +5 -2
- package/dist/commands/monad/pay.js +123 -0
- package/dist/commands/monad/reputation/check.d.ts +18 -0
- package/dist/commands/monad/reputation/check.js +103 -0
- package/dist/commands/monad/reputation/give.d.ts +15 -0
- package/dist/commands/monad/reputation/give.js +99 -0
- package/dist/commands/monad/x402/pay.d.ts +21 -0
- package/dist/commands/monad/x402/pay.js +224 -0
- package/dist/index.d.ts +10 -7
- package/dist/index.js +10 -7
- package/dist/monad.d.ts +424 -0
- package/dist/monad.js +186 -0
- package/dist/sdk.d.ts +62 -39
- package/dist/sdk.js +95 -8
- package/oclif.manifest.json +1304 -24
- package/package.json +45 -9
- package/dist/commands/identity/get.d.ts +0 -13
- package/dist/commands/identity/get.js +0 -59
- package/dist/commands/identity/register.d.ts +0 -12
- package/dist/commands/identity/register.js +0 -39
- package/dist/commands/jobs/create.js +0 -38
- package/dist/commands/pay.js +0 -33
- package/dist/commands/reputation/check.d.ts +0 -12
- package/dist/commands/reputation/check.js +0 -46
- package/dist/commands/reputation/give.d.ts +0 -12
- package/dist/commands/reputation/give.js +0 -45
- package/dist/commands/x402/pay.d.ts +0 -13
- package/dist/commands/x402/pay.js +0 -67
- package/dist/commands.test.d.ts +0 -1
- package/dist/commands.test.js +0 -141
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { type MonadAgentCard } from "../../../monad.js";
|
|
2
|
+
import { BaseMonadPluginCommand, type CommandIO, type InputSchema } from "../../../sdk.js";
|
|
3
|
+
export interface GetIdentityResult {
|
|
4
|
+
agentId: string;
|
|
5
|
+
owner: string;
|
|
6
|
+
walletAddress: string;
|
|
7
|
+
card?: MonadAgentCard;
|
|
8
|
+
chainId: number;
|
|
9
|
+
}
|
|
10
|
+
export declare class MonadIdentityGetCommand extends BaseMonadPluginCommand<GetIdentityResult> {
|
|
11
|
+
static description: string;
|
|
12
|
+
static requiresAuth: boolean;
|
|
13
|
+
static requiresInit: boolean;
|
|
14
|
+
protected readonly pluginCommandId = "monad:identity:get";
|
|
15
|
+
static readonly inputs: InputSchema;
|
|
16
|
+
static flags: any;
|
|
17
|
+
static args: any;
|
|
18
|
+
execute(io: CommandIO): Promise<GetIdentityResult>;
|
|
19
|
+
}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { resolveChain, erc8004IdentityAbi, } from "../../../monad.js";
|
|
2
|
+
import { BaseMonadPluginCommand, CommandError, InputFieldType, } from "../../../sdk.js";
|
|
3
|
+
import { PluginCommand, schemaToArgs } from "@metamask/agent-wallet/plugin";
|
|
4
|
+
export class MonadIdentityGetCommand extends BaseMonadPluginCommand {
|
|
5
|
+
static description = "Get agent identity details from Monad ERC-8004 Registry";
|
|
6
|
+
static requiresAuth = false;
|
|
7
|
+
static requiresInit = false;
|
|
8
|
+
pluginCommandId = "monad:identity:get";
|
|
9
|
+
static inputs = {
|
|
10
|
+
agentId: {
|
|
11
|
+
type: InputFieldType.Text,
|
|
12
|
+
flag: "agentId",
|
|
13
|
+
message: "Agent token ID in ERC-8004 registry",
|
|
14
|
+
required: true,
|
|
15
|
+
index: 0,
|
|
16
|
+
},
|
|
17
|
+
chainId: {
|
|
18
|
+
type: InputFieldType.Text,
|
|
19
|
+
flag: "chain-id",
|
|
20
|
+
aliases: ["chainId"],
|
|
21
|
+
message: "Monad chain ID (10143 for testnet, 143 for mainnet)",
|
|
22
|
+
required: false,
|
|
23
|
+
},
|
|
24
|
+
};
|
|
25
|
+
static flags = PluginCommand.flagsWithInputs(this.inputs);
|
|
26
|
+
static args = schemaToArgs(this.inputs);
|
|
27
|
+
async execute(io) {
|
|
28
|
+
const rawInputs = await io.resolveInputs(MonadIdentityGetCommand.inputs);
|
|
29
|
+
const agentId = String(rawInputs.agentId).trim();
|
|
30
|
+
if (!/^\d+$/.test(agentId)) {
|
|
31
|
+
throw new CommandError("INVALID_INPUT", `Invalid agentId "${agentId}". Must be a numeric string.`, "Provide a valid agent ID number (e.g. 1).");
|
|
32
|
+
}
|
|
33
|
+
const chain = resolveChain(rawInputs.chainId);
|
|
34
|
+
const client = this.getPublicClient(chain.chainId);
|
|
35
|
+
const tokenIdBigInt = BigInt(agentId);
|
|
36
|
+
let owner;
|
|
37
|
+
let walletAddress;
|
|
38
|
+
let tokenUri;
|
|
39
|
+
const registryAddress = chain.identityRegistry;
|
|
40
|
+
try {
|
|
41
|
+
[owner, walletAddress, tokenUri] = await Promise.all([
|
|
42
|
+
client.readContract({
|
|
43
|
+
address: registryAddress,
|
|
44
|
+
abi: erc8004IdentityAbi,
|
|
45
|
+
functionName: "ownerOf",
|
|
46
|
+
args: [tokenIdBigInt],
|
|
47
|
+
}),
|
|
48
|
+
client.readContract({
|
|
49
|
+
address: registryAddress,
|
|
50
|
+
abi: erc8004IdentityAbi,
|
|
51
|
+
functionName: "getAgentWallet",
|
|
52
|
+
args: [tokenIdBigInt],
|
|
53
|
+
}),
|
|
54
|
+
client.readContract({
|
|
55
|
+
address: registryAddress,
|
|
56
|
+
abi: erc8004IdentityAbi,
|
|
57
|
+
functionName: "tokenURI",
|
|
58
|
+
args: [tokenIdBigInt],
|
|
59
|
+
}),
|
|
60
|
+
]);
|
|
61
|
+
}
|
|
62
|
+
catch (err) {
|
|
63
|
+
throw new CommandError("AGENT_NOT_FOUND", `Failed to fetch Agent #${agentId} from Monad ERC-8004 Registry (${registryAddress} on chain ${chain.chainId}): ${err?.message || String(err)}`, "Verify the agentId exists on the specified chain.");
|
|
64
|
+
}
|
|
65
|
+
let card;
|
|
66
|
+
try {
|
|
67
|
+
let jsonString = "";
|
|
68
|
+
if (tokenUri.startsWith("data:application/json;base64,")) {
|
|
69
|
+
const base64Data = tokenUri.slice("data:application/json;base64,".length);
|
|
70
|
+
jsonString = Buffer.from(base64Data, "base64").toString("utf-8");
|
|
71
|
+
}
|
|
72
|
+
else if (tokenUri.startsWith("data:application/json;utf8,") || tokenUri.startsWith("data:application/json,")) {
|
|
73
|
+
const urlEncoded = tokenUri.replace(/^data:application\/json(;utf8)?,/, "");
|
|
74
|
+
jsonString = decodeURIComponent(urlEncoded);
|
|
75
|
+
}
|
|
76
|
+
else if (tokenUri.startsWith("{")) {
|
|
77
|
+
jsonString = tokenUri;
|
|
78
|
+
}
|
|
79
|
+
if (jsonString) {
|
|
80
|
+
const parsedJson = JSON.parse(jsonString);
|
|
81
|
+
card = {
|
|
82
|
+
name: parsedJson.name || `Agent #${agentId}`,
|
|
83
|
+
description: parsedJson.description || "",
|
|
84
|
+
walletAddress: walletAddress,
|
|
85
|
+
endpoints: parsedJson.services?.map((s) => s.endpoint).filter(Boolean) || [
|
|
86
|
+
parsedJson.endpoint || "",
|
|
87
|
+
],
|
|
88
|
+
supportedProtocols: parsedJson.supportedProtocols || ["mcp", "x402"],
|
|
89
|
+
active: parsedJson.active !== undefined ? Boolean(parsedJson.active) : true,
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
catch {
|
|
94
|
+
// If parsing fails, create card with available contract data
|
|
95
|
+
card = {
|
|
96
|
+
name: `Agent #${agentId}`,
|
|
97
|
+
description: "",
|
|
98
|
+
walletAddress: walletAddress,
|
|
99
|
+
endpoints: [],
|
|
100
|
+
supportedProtocols: ["mcp", "x402"],
|
|
101
|
+
active: true,
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
io.emit(`Agent #${agentId}: Owner: ${owner}, Wallet: ${walletAddress}, Name: ${card?.name || "N/A"}`);
|
|
105
|
+
return {
|
|
106
|
+
agentId,
|
|
107
|
+
owner,
|
|
108
|
+
walletAddress,
|
|
109
|
+
card,
|
|
110
|
+
chainId: chain.chainId,
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { type MonadAgentCard } from "../../../monad.js";
|
|
2
|
+
import { BaseMonadPluginCommand, type CommandIO, type InputSchema } from "../../../sdk.js";
|
|
3
|
+
export interface RegisterIdentityResult {
|
|
4
|
+
transactionHash: `0x${string}`;
|
|
5
|
+
agentId: string;
|
|
6
|
+
agentCard: MonadAgentCard;
|
|
7
|
+
registryAddress: string;
|
|
8
|
+
chainId: number;
|
|
9
|
+
}
|
|
10
|
+
export declare class MonadIdentityRegisterCommand extends BaseMonadPluginCommand<RegisterIdentityResult> {
|
|
11
|
+
static description: string;
|
|
12
|
+
protected readonly pluginCommandId = "monad:identity:register";
|
|
13
|
+
static readonly inputs: InputSchema;
|
|
14
|
+
static flags: any;
|
|
15
|
+
execute(io: CommandIO): Promise<RegisterIdentityResult>;
|
|
16
|
+
}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { encodeFunctionData, parseEventLogs } from "viem";
|
|
2
|
+
import { resolveChain, erc8004IdentityAbi, monadAgentCardSchema, } from "../../../monad.js";
|
|
3
|
+
import { BaseMonadPluginCommand, CommandError, InputFieldType, executeTransaction, } from "../../../sdk.js";
|
|
4
|
+
import { PluginCommand } from "@metamask/agent-wallet/plugin";
|
|
5
|
+
export class MonadIdentityRegisterCommand extends BaseMonadPluginCommand {
|
|
6
|
+
static description = "Register an AI Agent identity on Monad ERC-8004 Registry";
|
|
7
|
+
pluginCommandId = "monad:identity:register";
|
|
8
|
+
static inputs = {
|
|
9
|
+
name: {
|
|
10
|
+
type: InputFieldType.Text,
|
|
11
|
+
flag: "name",
|
|
12
|
+
message: "Human-readable agent name",
|
|
13
|
+
required: true,
|
|
14
|
+
},
|
|
15
|
+
description: {
|
|
16
|
+
type: InputFieldType.Text,
|
|
17
|
+
flag: "description",
|
|
18
|
+
message: "Agent description and capabilities",
|
|
19
|
+
required: true,
|
|
20
|
+
},
|
|
21
|
+
walletAddress: {
|
|
22
|
+
type: InputFieldType.Text,
|
|
23
|
+
flag: "walletAddress",
|
|
24
|
+
message: "Agent operational EVM wallet address",
|
|
25
|
+
required: true,
|
|
26
|
+
},
|
|
27
|
+
endpoint: {
|
|
28
|
+
type: InputFieldType.Text,
|
|
29
|
+
flag: "endpoint",
|
|
30
|
+
message: "Primary service endpoint URL",
|
|
31
|
+
required: false,
|
|
32
|
+
},
|
|
33
|
+
chainId: {
|
|
34
|
+
type: InputFieldType.Text,
|
|
35
|
+
flag: "chain-id",
|
|
36
|
+
aliases: ["chainId"],
|
|
37
|
+
message: "Monad chain ID (10143 for testnet, 143 for mainnet)",
|
|
38
|
+
required: false,
|
|
39
|
+
},
|
|
40
|
+
};
|
|
41
|
+
static flags = PluginCommand.flagsWithInputs(this.inputs);
|
|
42
|
+
async execute(io) {
|
|
43
|
+
const rawInputs = await io.resolveInputs(MonadIdentityRegisterCommand.inputs);
|
|
44
|
+
const chain = resolveChain(rawInputs.chainId);
|
|
45
|
+
const cardInput = {
|
|
46
|
+
name: rawInputs.name,
|
|
47
|
+
description: rawInputs.description,
|
|
48
|
+
walletAddress: rawInputs.walletAddress,
|
|
49
|
+
endpoints: [rawInputs.endpoint || "https://agent.xyz"],
|
|
50
|
+
supportedProtocols: ["mcp", "x402"],
|
|
51
|
+
active: true,
|
|
52
|
+
};
|
|
53
|
+
const parsedCard = monadAgentCardSchema.safeParse(cardInput);
|
|
54
|
+
if (!parsedCard.success) {
|
|
55
|
+
throw new CommandError("INVALID_INPUT", `Invalid agent card input: ${parsedCard.error.issues.map((i) => i.message).join(", ")}`, "Check agent name, description, wallet address, and endpoint.");
|
|
56
|
+
}
|
|
57
|
+
const card = parsedCard.data;
|
|
58
|
+
// Build standard ERC-8004 Registration JSON data URI
|
|
59
|
+
const registrationJson = {
|
|
60
|
+
type: "https://eips.ethereum.org/EIPS/eip-8004#registration-v1",
|
|
61
|
+
name: card.name,
|
|
62
|
+
description: card.description,
|
|
63
|
+
image: "https://i.imgur.com/JQxM4nO.png",
|
|
64
|
+
services: [
|
|
65
|
+
{
|
|
66
|
+
name: "A2A",
|
|
67
|
+
endpoint: card.endpoints[0],
|
|
68
|
+
version: "0.3.0",
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
name: "MCP",
|
|
72
|
+
endpoint: `${card.endpoints[0]}/mcp`,
|
|
73
|
+
version: "2025-06-18",
|
|
74
|
+
},
|
|
75
|
+
],
|
|
76
|
+
x402Support: card.supportedProtocols.includes("x402"),
|
|
77
|
+
active: card.active,
|
|
78
|
+
registrations: [],
|
|
79
|
+
supportedTrust: ["reputation"],
|
|
80
|
+
};
|
|
81
|
+
const agentUri = `data:application/json;base64,${Buffer.from(JSON.stringify(registrationJson)).toString("base64")}`;
|
|
82
|
+
const data = encodeFunctionData({
|
|
83
|
+
abi: erc8004IdentityAbi,
|
|
84
|
+
functionName: "register",
|
|
85
|
+
args: [agentUri],
|
|
86
|
+
});
|
|
87
|
+
const hash = await executeTransaction(this.ctx, io, this.pluginCommandId, {
|
|
88
|
+
chainId: chain.chainId,
|
|
89
|
+
to: chain.identityRegistry,
|
|
90
|
+
data,
|
|
91
|
+
});
|
|
92
|
+
// Extract agentId from Registered event log
|
|
93
|
+
let onChainAgentId;
|
|
94
|
+
try {
|
|
95
|
+
const client = this.getPublicClient(chain.chainId);
|
|
96
|
+
const receipt = await client.waitForTransactionReceipt({ hash });
|
|
97
|
+
const logs = parseEventLogs({
|
|
98
|
+
abi: erc8004IdentityAbi,
|
|
99
|
+
logs: receipt.logs,
|
|
100
|
+
eventName: "Registered",
|
|
101
|
+
});
|
|
102
|
+
if (logs.length > 0 && logs[0].args.agentId !== undefined) {
|
|
103
|
+
onChainAgentId = logs[0].args.agentId.toString();
|
|
104
|
+
}
|
|
105
|
+
else {
|
|
106
|
+
throw new Error("Registered event not found in receipt");
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
catch (err) {
|
|
110
|
+
throw new CommandError("RECEIPT_PARSING_FAILED", `Agent registration confirmed in tx ${hash}, but Registered event log could not be parsed: ${err?.message || String(err)}`, "Check transaction on Monad Explorer.");
|
|
111
|
+
}
|
|
112
|
+
io.emit(`Agent #${onChainAgentId} registered on ${chain.name} ERC-8004 Registry! TxHash: ${hash}`);
|
|
113
|
+
io.emit(`Explorer: ${chain.explorerUrl}/tx/${hash}`);
|
|
114
|
+
return {
|
|
115
|
+
transactionHash: hash,
|
|
116
|
+
agentId: onChainAgentId,
|
|
117
|
+
agentCard: card,
|
|
118
|
+
registryAddress: chain.identityRegistry,
|
|
119
|
+
chainId: chain.chainId,
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { BaseMonadPluginCommand, type CommandIO, type InputSchema } from "../../../sdk.js";
|
|
2
|
+
export interface CompleteJobResult {
|
|
3
|
+
jobId: string;
|
|
4
|
+
resultURI: string;
|
|
5
|
+
transactionHash: `0x${string}`;
|
|
6
|
+
chainId: number;
|
|
7
|
+
}
|
|
8
|
+
export declare class MonadJobsCompleteCommand extends BaseMonadPluginCommand<CompleteJobResult> {
|
|
9
|
+
static description: string;
|
|
10
|
+
protected readonly pluginCommandId = "monad:jobs:complete";
|
|
11
|
+
static readonly inputs: InputSchema;
|
|
12
|
+
static flags: any;
|
|
13
|
+
static args: any;
|
|
14
|
+
execute(io: CommandIO): Promise<CompleteJobResult>;
|
|
15
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { encodeFunctionData } from "viem";
|
|
2
|
+
import { resolveChain, monadEscrowAbi, monadCompleteJobSchema, } from "../../../monad.js";
|
|
3
|
+
import { BaseMonadPluginCommand, CommandError, InputFieldType, executeTransaction, } from "../../../sdk.js";
|
|
4
|
+
import { PluginCommand, schemaToArgs } from "@metamask/agent-wallet/plugin";
|
|
5
|
+
export class MonadJobsCompleteCommand extends BaseMonadPluginCommand {
|
|
6
|
+
static description = "Complete and release a subcontracted A2A task escrow on Monad";
|
|
7
|
+
pluginCommandId = "monad:jobs:complete";
|
|
8
|
+
static inputs = {
|
|
9
|
+
jobId: {
|
|
10
|
+
type: InputFieldType.Text,
|
|
11
|
+
flag: "jobId",
|
|
12
|
+
message: "Escrow job ID to complete",
|
|
13
|
+
required: true,
|
|
14
|
+
index: 0,
|
|
15
|
+
},
|
|
16
|
+
resultURI: {
|
|
17
|
+
type: InputFieldType.Text,
|
|
18
|
+
flag: "resultURI",
|
|
19
|
+
message: "Deliverable URI or proof hash",
|
|
20
|
+
required: false,
|
|
21
|
+
},
|
|
22
|
+
chainId: {
|
|
23
|
+
type: InputFieldType.Text,
|
|
24
|
+
flag: "chain-id",
|
|
25
|
+
aliases: ["chainId"],
|
|
26
|
+
message: "Monad chain ID (10143 for testnet, 143 for mainnet)",
|
|
27
|
+
required: false,
|
|
28
|
+
},
|
|
29
|
+
};
|
|
30
|
+
static flags = PluginCommand.flagsWithInputs(this.inputs);
|
|
31
|
+
static args = schemaToArgs(this.inputs);
|
|
32
|
+
async execute(io) {
|
|
33
|
+
const rawInputs = await io.resolveInputs(MonadJobsCompleteCommand.inputs);
|
|
34
|
+
const parsed = monadCompleteJobSchema.safeParse(rawInputs);
|
|
35
|
+
if (!parsed.success) {
|
|
36
|
+
throw new CommandError("INVALID_INPUT", `Invalid complete job input: ${parsed.error.issues.map((i) => i.message).join(", ")}`, "Provide a numeric jobId and optional resultURI.");
|
|
37
|
+
}
|
|
38
|
+
const { jobId, resultURI } = parsed.data;
|
|
39
|
+
const chain = resolveChain(rawInputs.chainId);
|
|
40
|
+
if (!chain.escrow) {
|
|
41
|
+
throw new CommandError("ESCROW_NOT_DEPLOYED", `MonadA2AEscrow is not deployed on Monad chain ${chain.chainId}. Escrow is currently available on Monad Testnet (10143).`, "Specify --chain-id 10143 to interact with escrow contracts.");
|
|
42
|
+
}
|
|
43
|
+
io.emit(`Releasing escrow for Job #${jobId} on ${chain.name}...`);
|
|
44
|
+
const data = encodeFunctionData({
|
|
45
|
+
abi: monadEscrowAbi,
|
|
46
|
+
functionName: "completeJob",
|
|
47
|
+
args: [BigInt(jobId), resultURI],
|
|
48
|
+
});
|
|
49
|
+
const hash = await executeTransaction(this.ctx, io, this.pluginCommandId, {
|
|
50
|
+
chainId: chain.chainId,
|
|
51
|
+
to: chain.escrow,
|
|
52
|
+
data,
|
|
53
|
+
});
|
|
54
|
+
io.emit(`Job #${jobId} escrow released and settled on ${chain.name}! TxHash: ${hash}`);
|
|
55
|
+
io.emit(`Explorer: ${chain.explorerUrl}/tx/${hash}`);
|
|
56
|
+
return {
|
|
57
|
+
jobId,
|
|
58
|
+
resultURI,
|
|
59
|
+
transactionHash: hash,
|
|
60
|
+
chainId: chain.chainId,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
}
|
|
@@ -1,13 +1,16 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { BaseMonadPluginCommand, type CommandIO, type InputSchema } from "../../../sdk.js";
|
|
2
2
|
export interface CreateJobResult {
|
|
3
3
|
jobId: string;
|
|
4
4
|
workerAddress: string;
|
|
5
5
|
bountyMon: string;
|
|
6
6
|
taskDescription: string;
|
|
7
7
|
escrowTransactionHash: `0x${string}`;
|
|
8
|
+
chainId: number;
|
|
8
9
|
}
|
|
9
|
-
export declare class MonadJobsCreateCommand extends
|
|
10
|
+
export declare class MonadJobsCreateCommand extends BaseMonadPluginCommand<CreateJobResult> {
|
|
10
11
|
static description: string;
|
|
11
12
|
protected readonly pluginCommandId = "monad:jobs:create";
|
|
13
|
+
static readonly inputs: InputSchema;
|
|
14
|
+
static flags: any;
|
|
12
15
|
execute(io: CommandIO): Promise<CreateJobResult>;
|
|
13
16
|
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { encodeFunctionData, parseEther, parseEventLogs } from "viem";
|
|
2
|
+
import { resolveChain, monadEscrowAbi, monadCreateJobSchema, } from "../../../monad.js";
|
|
3
|
+
import { BaseMonadPluginCommand, CommandError, InputFieldType, executeTransaction, } from "../../../sdk.js";
|
|
4
|
+
import { PluginCommand } from "@metamask/agent-wallet/plugin";
|
|
5
|
+
export class MonadJobsCreateCommand extends BaseMonadPluginCommand {
|
|
6
|
+
static description = "Create and fund a subcontracted A2A task escrow on Monad";
|
|
7
|
+
pluginCommandId = "monad:jobs:create";
|
|
8
|
+
static inputs = {
|
|
9
|
+
workerAddress: {
|
|
10
|
+
type: InputFieldType.Text,
|
|
11
|
+
flag: "workerAddress",
|
|
12
|
+
message: "Worker EVM address receiving the escrow bounty",
|
|
13
|
+
required: true,
|
|
14
|
+
},
|
|
15
|
+
bountyMon: {
|
|
16
|
+
type: InputFieldType.Text,
|
|
17
|
+
flag: "bountyMon",
|
|
18
|
+
message: "Bounty amount in native MON (e.g. 0.2)",
|
|
19
|
+
required: true,
|
|
20
|
+
},
|
|
21
|
+
taskDescription: {
|
|
22
|
+
type: InputFieldType.Text,
|
|
23
|
+
flag: "taskDescription",
|
|
24
|
+
message: "Clear deliverable description or specifications",
|
|
25
|
+
required: true,
|
|
26
|
+
},
|
|
27
|
+
deadlineHours: {
|
|
28
|
+
type: InputFieldType.Text,
|
|
29
|
+
flag: "deadlineHours",
|
|
30
|
+
message: "Review and task window in hours (default 24)",
|
|
31
|
+
required: false,
|
|
32
|
+
},
|
|
33
|
+
chainId: {
|
|
34
|
+
type: InputFieldType.Text,
|
|
35
|
+
flag: "chain-id",
|
|
36
|
+
aliases: ["chainId"],
|
|
37
|
+
message: "Monad chain ID (10143 for testnet, 143 for mainnet)",
|
|
38
|
+
required: false,
|
|
39
|
+
},
|
|
40
|
+
};
|
|
41
|
+
static flags = PluginCommand.flagsWithInputs(this.inputs);
|
|
42
|
+
async execute(io) {
|
|
43
|
+
const rawInputs = await io.resolveInputs(MonadJobsCreateCommand.inputs);
|
|
44
|
+
const parsed = monadCreateJobSchema.safeParse(rawInputs);
|
|
45
|
+
if (!parsed.success) {
|
|
46
|
+
throw new CommandError("INVALID_INPUT", `Invalid job creation input: ${parsed.error.issues.map((i) => i.message).join(", ")}`, "Provide valid workerAddress, positive bountyMon, and taskDescription.");
|
|
47
|
+
}
|
|
48
|
+
const { workerAddress, bountyMon, taskDescription, deadlineHours } = parsed.data;
|
|
49
|
+
const chain = resolveChain(rawInputs.chainId);
|
|
50
|
+
if (!chain.escrow) {
|
|
51
|
+
throw new CommandError("ESCROW_NOT_DEPLOYED", `MonadA2AEscrow is not deployed on Monad chain ${chain.chainId}. Escrow is currently available on Monad Testnet (10143).`, "Specify --chain-id 10143 to interact with escrow contracts.");
|
|
52
|
+
}
|
|
53
|
+
io.emit(`Creating A2A Job on ${chain.name} for worker ${workerAddress} with bounty ${bountyMon} MON (Deadline: ${deadlineHours}h)...`);
|
|
54
|
+
const data = encodeFunctionData({
|
|
55
|
+
abi: monadEscrowAbi,
|
|
56
|
+
functionName: "createAndFundJob",
|
|
57
|
+
args: [workerAddress, taskDescription, BigInt(deadlineHours)],
|
|
58
|
+
});
|
|
59
|
+
const hash = await executeTransaction(this.ctx, io, this.pluginCommandId, {
|
|
60
|
+
chainId: chain.chainId,
|
|
61
|
+
to: chain.escrow,
|
|
62
|
+
value: parseEther(bountyMon),
|
|
63
|
+
data,
|
|
64
|
+
});
|
|
65
|
+
// Wait for receipt and decode JobCreated event
|
|
66
|
+
const client = this.getPublicClient(chain.chainId);
|
|
67
|
+
const receipt = await client.waitForTransactionReceipt({ hash });
|
|
68
|
+
const logs = parseEventLogs({
|
|
69
|
+
abi: monadEscrowAbi,
|
|
70
|
+
logs: receipt.logs,
|
|
71
|
+
eventName: "JobCreated",
|
|
72
|
+
});
|
|
73
|
+
if (logs.length === 0 || logs[0].args.jobId === undefined) {
|
|
74
|
+
throw new CommandError("RECEIPT_PARSING_FAILED", `Transaction ${hash} confirmed, but JobCreated event was not found in receipt logs.`, "Check escrow contract address and receipt on Monad Explorer.");
|
|
75
|
+
}
|
|
76
|
+
const onChainJobId = logs[0].args.jobId.toString();
|
|
77
|
+
io.emit(`Job escrow funded on ${chain.name}! JobId: ${onChainJobId}, TxHash: ${hash}`);
|
|
78
|
+
io.emit(`Explorer: ${chain.explorerUrl}/tx/${hash}`);
|
|
79
|
+
return {
|
|
80
|
+
jobId: onChainJobId,
|
|
81
|
+
workerAddress,
|
|
82
|
+
bountyMon,
|
|
83
|
+
taskDescription,
|
|
84
|
+
escrowTransactionHash: hash,
|
|
85
|
+
chainId: chain.chainId,
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { BaseMonadPluginCommand, type CommandIO, type InputSchema } from "../../../sdk.js";
|
|
2
|
+
export interface RefundJobResult {
|
|
3
|
+
jobId: string;
|
|
4
|
+
transactionHash: `0x${string}`;
|
|
5
|
+
chainId: number;
|
|
6
|
+
}
|
|
7
|
+
export declare class MonadJobsRefundCommand extends BaseMonadPluginCommand<RefundJobResult> {
|
|
8
|
+
static description: string;
|
|
9
|
+
protected readonly pluginCommandId = "monad:jobs:refund";
|
|
10
|
+
static readonly inputs: InputSchema;
|
|
11
|
+
static flags: any;
|
|
12
|
+
static args: any;
|
|
13
|
+
execute(io: CommandIO): Promise<RefundJobResult>;
|
|
14
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { encodeFunctionData } from "viem";
|
|
2
|
+
import { resolveChain, monadEscrowAbi, monadRefundJobSchema, } from "../../../monad.js";
|
|
3
|
+
import { BaseMonadPluginCommand, CommandError, InputFieldType, executeTransaction, } from "../../../sdk.js";
|
|
4
|
+
import { PluginCommand, schemaToArgs } from "@metamask/agent-wallet/plugin";
|
|
5
|
+
export class MonadJobsRefundCommand extends BaseMonadPluginCommand {
|
|
6
|
+
static description = "Refund an expired subcontracted A2A task escrow on Monad";
|
|
7
|
+
pluginCommandId = "monad:jobs:refund";
|
|
8
|
+
static inputs = {
|
|
9
|
+
jobId: {
|
|
10
|
+
type: InputFieldType.Text,
|
|
11
|
+
flag: "jobId",
|
|
12
|
+
message: "Escrow job ID to refund after deadline",
|
|
13
|
+
required: true,
|
|
14
|
+
index: 0,
|
|
15
|
+
},
|
|
16
|
+
chainId: {
|
|
17
|
+
type: InputFieldType.Text,
|
|
18
|
+
flag: "chain-id",
|
|
19
|
+
aliases: ["chainId"],
|
|
20
|
+
message: "Monad chain ID (10143 for testnet, 143 for mainnet)",
|
|
21
|
+
required: false,
|
|
22
|
+
},
|
|
23
|
+
};
|
|
24
|
+
static flags = PluginCommand.flagsWithInputs(this.inputs);
|
|
25
|
+
static args = schemaToArgs(this.inputs);
|
|
26
|
+
async execute(io) {
|
|
27
|
+
const rawInputs = await io.resolveInputs(MonadJobsRefundCommand.inputs);
|
|
28
|
+
const parsed = monadRefundJobSchema.safeParse(rawInputs);
|
|
29
|
+
if (!parsed.success) {
|
|
30
|
+
throw new CommandError("INVALID_INPUT", `Invalid refund job input: ${parsed.error.issues.map((i) => i.message).join(", ")}`, "Provide a numeric jobId.");
|
|
31
|
+
}
|
|
32
|
+
const { jobId } = parsed.data;
|
|
33
|
+
const chain = resolveChain(rawInputs.chainId);
|
|
34
|
+
if (!chain.escrow) {
|
|
35
|
+
throw new CommandError("ESCROW_NOT_DEPLOYED", `MonadA2AEscrow is not deployed on Monad chain ${chain.chainId}. Escrow is currently available on Monad Testnet (10143).`, "Specify --chain-id 10143 to interact with escrow contracts.");
|
|
36
|
+
}
|
|
37
|
+
io.emit(`Refunding expired escrow for Job #${jobId} on ${chain.name}...`);
|
|
38
|
+
const data = encodeFunctionData({
|
|
39
|
+
abi: monadEscrowAbi,
|
|
40
|
+
functionName: "refundExpiredJob",
|
|
41
|
+
args: [BigInt(jobId)],
|
|
42
|
+
});
|
|
43
|
+
const hash = await executeTransaction(this.ctx, io, this.pluginCommandId, {
|
|
44
|
+
chainId: chain.chainId,
|
|
45
|
+
to: chain.escrow,
|
|
46
|
+
data,
|
|
47
|
+
});
|
|
48
|
+
io.emit(`Job #${jobId} escrow refunded on ${chain.name}! TxHash: ${hash}`);
|
|
49
|
+
io.emit(`Explorer: ${chain.explorerUrl}/tx/${hash}`);
|
|
50
|
+
return {
|
|
51
|
+
jobId,
|
|
52
|
+
transactionHash: hash,
|
|
53
|
+
chainId: chain.chainId,
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
}
|
|
@@ -1,13 +1,16 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { BaseMonadPluginCommand, type CommandIO, type InputSchema } from "../../sdk.js";
|
|
2
2
|
export interface MonadPaymentResult {
|
|
3
3
|
transactionHash: `0x${string}`;
|
|
4
4
|
to: string;
|
|
5
5
|
amount: string;
|
|
6
6
|
token: string;
|
|
7
7
|
memo?: string;
|
|
8
|
+
chainId: number;
|
|
8
9
|
}
|
|
9
|
-
export declare class MonadPayCommand extends
|
|
10
|
+
export declare class MonadPayCommand extends BaseMonadPluginCommand<MonadPaymentResult> {
|
|
10
11
|
static description: string;
|
|
11
12
|
protected readonly pluginCommandId = "monad:pay";
|
|
13
|
+
static readonly inputs: InputSchema;
|
|
14
|
+
static flags: any;
|
|
12
15
|
execute(io: CommandIO): Promise<MonadPaymentResult>;
|
|
13
16
|
}
|