@ton-agent-kit/plugin-token 1.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/package.json +17 -0
- package/src/actions/deploy-jetton.ts +134 -0
- package/src/actions/get-balance.ts +48 -0
- package/src/actions/get-jetton-balance.ts +69 -0
- package/src/actions/get-jetton-info.ts +33 -0
- package/src/actions/transfer-jetton.ts +77 -0
- package/src/actions/transfer-ton.ts +76 -0
- package/src/index.ts +42 -0
- package/tsconfig.json +5 -0
package/package.json
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@ton-agent-kit/plugin-token",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Token operations plugin for TON Agent Kit — TON transfers, Jetton operations",
|
|
5
|
+
"main": "src/index.ts",
|
|
6
|
+
"types": "src/index.ts",
|
|
7
|
+
"scripts": { "build": "tsc" },
|
|
8
|
+
"dependencies": {
|
|
9
|
+
"@ton-agent-kit/core": "^1.0.0",
|
|
10
|
+
"@ton/ton": "^16.2.0",
|
|
11
|
+
"@ton/core": "^0.63.1"
|
|
12
|
+
},
|
|
13
|
+
"keywords": ["ton", "blockchain", "ai", "agent", "sdk"],
|
|
14
|
+
"license": "MIT",
|
|
15
|
+
"publishConfig": { "access": "public" },
|
|
16
|
+
"repository": { "type": "git", "url": "https://github.com/Andy00L/ton-agent-kit.git" }
|
|
17
|
+
}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { toNano, beginCell, Cell, Dictionary, internal, contractAddress } from "@ton/core";
|
|
3
|
+
import { defineAction, sendTransaction, explorerUrl } from "@ton-agent-kit/core";
|
|
4
|
+
import { createHash } from "crypto";
|
|
5
|
+
|
|
6
|
+
// Standard Jetton minter compiled code (from ton-blockchain/minter)
|
|
7
|
+
const JETTON_MINTER_CODE_HEX =
|
|
8
|
+
"b5ee9c72c1020d0100029c000000000d00120018002a006b007000bc0139018f02110218027b0114ff00f4a413f4bcf2c80b01020162050202037a600403001faf16f6a2687d007d206a6a183faa9040007dadbcf6a2687d007d206a6a183618fc1400b82a1009aa0a01e428027d012c678b00e78b666491646580897a007a00658064fc80383a6465816503e5ffe4e8400202cc07060093b5f0508806e0a84026a8280790a009f404b19e2c039e2d99924591960225e801e80196019241f200e0e9919605940f97ff93a0ef003191960ab19e2ca009f4042796d625999992e3f60102f1d906380492f81f000e8698180b8d8492f81f07d207d2018fd0018b8eb90fd0018fd001801698fe99ff6a2687d007d206a6a18400aa9385d47199a9a9b1b289a6382f97024817d207d006a18106840306b90fd001812881a282178050a502819e428027d012c678b666664f6aa7041083deecbef29385d718140b0801a682102c76b9735270bae30235373723c0038e1a335035c705f2e04903fa403059c85004fa0258cf16ccccc9ed54e03502c0048e185124c705f2e049d4304300c85004fa0258cf16ccccc9ed54e05f05840ff2f00901fe365f03820898968015a015bcf2e04b02fa40d3003095c821cf16c9916de28210d1735400708018c8cb055005cf1624fa0214cb6a13cb1f14cb3f23fa443070ba8e33f828440370542013541403c85004fa0258cf1601cf16ccc922c8cb0112f400f400cb00c9f9007074c8cb02ca07cbffc9d0cf16966c227001cb01e2f4000a000ac98040fb0001c036373701fa00fa40f82854120670542013541403c85004fa0258cf1601cf16ccc922c8cb0112f400f400cb00c9f9007074c8cb02ca07cbffc9d05006c705f2e04aa1034545c85004fa0258cf16ccccc9ed5401fa403020d70b01c300915be30d0c003e8210d53276db708010c8cb055003cf1622fa0212cb6acb1fcb3fc98042fb002eedfd83";
|
|
9
|
+
|
|
10
|
+
const JETTON_WALLET_CODE_HEX =
|
|
11
|
+
"b5ee9c72c1021101000323000000000d001200220027002c00700075007a00e8016801a801e2025e02af02b402bf0114ff00f4a413f4bcf2c80b010201620302001ba0f605da89a1f401f481f481a8610202cc0e0402012006050083d40106b90f6a2687d007d207d206a1802698fc1080bc6a28ca9105d41083deecbef09dd0958f97162e99f98fd001809d02811e428027d012c678b00e78b6664f6aa40201200c07020120090800d73b51343e803e903e90350c01f4cffe803e900c145468549271c17cb8b049f0bffcb8b08160824c4b402805af3cb8b0e0841ef765f7b232c7c572cfd400fe8088b3c58073c5b25c60063232c14933c59c3e80b2dab33260103ec01004f214013e809633c58073c5b3327b552002f73b51343e803e903e90350c0234cffe80145468017e903e9014d6f1c1551cdb5c150804d50500f214013e809633c58073c5b33248b232c044bd003d0032c0327e401c1d3232c0b281f2fff274140371c1472c7cb8b0c2be80146a2860822625a019ad822860822625a028062849e5c412440e0dd7c138c34975c2c0600b0a007cc30023c200b08e218210d53276db708010c8cb055008cf165004fa0216cb6a12cb1f12cb3fc972fb0093356c21e203c85004fa0258cf1601cf16ccc9ed5400705279a018a182107362d09cc8cb1f5230cb3f58fa025007cf165007cf16c9718010c8cb0524cf165006fa0215cb6a14ccc971fb001024102301f1503d33ffa00fa4021f001ed44d0fa00fa40fa40d4305136a1522ac705f2e2c128c2fff2e2c254344270542013541403c85004fa0258cf1601cf16ccc922c8cb0112f400f400cb00c920f9007074c8cb02ca07cbffc9d004fa40f40431fa0020d749c200f2e2c4778018c8cb055008cf1670fa0217cb6b13cc80d009e8210178d4519c8cb1f19cb3f5007fa0222cf165006cf1625fa025003cf16c95005cc2391729171e25008a813a08209c9c380a014bcf2e2c504c98040fb001023c85004fa0258cf1601cf16ccc9ed540201d4100f00113e910c1c2ebcb8536000c30831c02497c138007434c0c05c6c2544d7c0fc03383e903e900c7e800c5c75c87e800c7e800c1cea6d0000b4c7e08403e29fa954882ea54c4d167c0278208405e3514654882ea58c511100fc02b80d60841657c1ef2ea4d67c02f817c12103fcbc200475cc36";
|
|
12
|
+
|
|
13
|
+
export const deployJettonAction = defineAction<
|
|
14
|
+
{ name: string; symbol: string; description?: string; decimals?: number; initialSupply?: string },
|
|
15
|
+
any
|
|
16
|
+
>({
|
|
17
|
+
name: "deploy_jetton",
|
|
18
|
+
description:
|
|
19
|
+
"Deploy a new Jetton (token) on TON blockchain. Creates a new token with the specified name, symbol, and initial supply.",
|
|
20
|
+
schema: z.object({
|
|
21
|
+
name: z.string().describe("Token name (e.g., 'My Token')"),
|
|
22
|
+
symbol: z.string().describe("Token symbol (e.g., 'MTK')"),
|
|
23
|
+
description: z.string().optional().describe("Token description"),
|
|
24
|
+
decimals: z.number().optional().describe("Token decimals (default: 9)"),
|
|
25
|
+
initialSupply: z.string().optional().describe("Initial supply in token units (default: 1000000)"),
|
|
26
|
+
}) as any,
|
|
27
|
+
handler: async (agent, params) => {
|
|
28
|
+
const ownerAddress = agent.wallet.address;
|
|
29
|
+
const decimals = params.decimals ?? 9;
|
|
30
|
+
const supply = params.initialSupply ?? "1000000";
|
|
31
|
+
|
|
32
|
+
// Load compiled contract code cells
|
|
33
|
+
const minterCode = Cell.fromBoc(Buffer.from(JETTON_MINTER_CODE_HEX, "hex"))[0];
|
|
34
|
+
const walletCode = Cell.fromBoc(Buffer.from(JETTON_WALLET_CODE_HEX, "hex"))[0];
|
|
35
|
+
|
|
36
|
+
// Build TEP-64 on-chain metadata content cell
|
|
37
|
+
const contentCell = buildTokenMetadataCell({
|
|
38
|
+
name: params.name,
|
|
39
|
+
symbol: params.symbol,
|
|
40
|
+
description: params.description || "",
|
|
41
|
+
decimals: decimals.toString(),
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
// Build Jetton minter initial data cell:
|
|
45
|
+
// total_supply:Coins admin_address:MsgAddress content:^Cell jetton_wallet_code:^Cell
|
|
46
|
+
const dataCell = beginCell()
|
|
47
|
+
.storeCoins(0) // total_supply starts at 0 (minted via internal mint msg)
|
|
48
|
+
.storeAddress(ownerAddress) // admin address
|
|
49
|
+
.storeRef(contentCell) // on-chain metadata
|
|
50
|
+
.storeRef(walletCode) // jetton wallet code
|
|
51
|
+
.endCell();
|
|
52
|
+
|
|
53
|
+
// Compute the new contract address from stateInit
|
|
54
|
+
const stateInit = { code: minterCode, data: dataCell };
|
|
55
|
+
const jettonMasterAddress = contractAddress(0, stateInit);
|
|
56
|
+
|
|
57
|
+
// Build mint message body (op::mint = 21, query_id, to, amount, ...)
|
|
58
|
+
const mintAmount = BigInt(Math.floor(parseFloat(supply) * Math.pow(10, decimals)));
|
|
59
|
+
const mintBody = beginCell()
|
|
60
|
+
.storeUint(21, 32) // op::mint
|
|
61
|
+
.storeUint(0, 64) // query_id
|
|
62
|
+
.storeAddress(ownerAddress) // to_address
|
|
63
|
+
.storeCoins(toNano("0.05")) // forward_ton_amount (gas for internal transfer)
|
|
64
|
+
.storeRef(
|
|
65
|
+
beginCell()
|
|
66
|
+
.storeUint(0x178d4519, 32) // op::internal_transfer
|
|
67
|
+
.storeUint(0, 64) // query_id
|
|
68
|
+
.storeCoins(mintAmount) // jetton_amount
|
|
69
|
+
.storeAddress(null) // from_address (null = minter)
|
|
70
|
+
.storeAddress(ownerAddress) // response_address
|
|
71
|
+
.storeCoins(0) // forward_ton_amount
|
|
72
|
+
.storeBit(false) // no forward payload
|
|
73
|
+
.endCell(),
|
|
74
|
+
)
|
|
75
|
+
.endCell();
|
|
76
|
+
|
|
77
|
+
// Send deploy + mint message
|
|
78
|
+
await sendTransaction(agent, [
|
|
79
|
+
internal({
|
|
80
|
+
to: jettonMasterAddress,
|
|
81
|
+
value: toNano("0.25"),
|
|
82
|
+
bounce: false,
|
|
83
|
+
init: stateInit,
|
|
84
|
+
body: mintBody,
|
|
85
|
+
}),
|
|
86
|
+
]);
|
|
87
|
+
|
|
88
|
+
const friendlyAddress = jettonMasterAddress.toString({
|
|
89
|
+
bounceable: true,
|
|
90
|
+
testOnly: agent.network === "testnet",
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
return {
|
|
94
|
+
txHash: "pending",
|
|
95
|
+
status: "deployed",
|
|
96
|
+
jettonAddress: jettonMasterAddress.toRawString(),
|
|
97
|
+
friendlyJettonAddress: friendlyAddress,
|
|
98
|
+
explorerUrl: explorerUrl("pending", agent.network),
|
|
99
|
+
fee: "~0.25 TON",
|
|
100
|
+
name: params.name,
|
|
101
|
+
symbol: params.symbol,
|
|
102
|
+
supply,
|
|
103
|
+
};
|
|
104
|
+
},
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Build on-chain metadata following TEP-64 standard.
|
|
109
|
+
* Uses a dictionary with SHA-256 hashed keys.
|
|
110
|
+
*/
|
|
111
|
+
function buildTokenMetadataCell(data: Record<string, string>): Cell {
|
|
112
|
+
const ONCHAIN_CONTENT_PREFIX = 0x00;
|
|
113
|
+
const SNAKE_PREFIX = 0x00;
|
|
114
|
+
|
|
115
|
+
// Build dictionary with 256-bit keys (SHA-256 of metadata key names)
|
|
116
|
+
const dict = Dictionary.empty(Dictionary.Keys.Buffer(32), Dictionary.Values.Cell());
|
|
117
|
+
|
|
118
|
+
for (const [key, value] of Object.entries(data)) {
|
|
119
|
+
if (!value) continue;
|
|
120
|
+
|
|
121
|
+
const keyHash = createHash("sha256").update(key).digest();
|
|
122
|
+
const valueCell = beginCell()
|
|
123
|
+
.storeUint(SNAKE_PREFIX, 8)
|
|
124
|
+
.storeStringTail(value)
|
|
125
|
+
.endCell();
|
|
126
|
+
|
|
127
|
+
dict.set(keyHash, valueCell);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
return beginCell()
|
|
131
|
+
.storeUint(ONCHAIN_CONTENT_PREFIX, 8)
|
|
132
|
+
.storeDict(dict)
|
|
133
|
+
.endCell();
|
|
134
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { Address, fromNano } from "@ton/core";
|
|
3
|
+
import { defineAction, type BalanceResult, toFriendlyAddress } from "@ton-agent-kit/core";
|
|
4
|
+
|
|
5
|
+
export const getBalanceAction = defineAction<{ address?: string }, BalanceResult>({
|
|
6
|
+
name: "get_balance",
|
|
7
|
+
description:
|
|
8
|
+
"Get the TON balance of a wallet address. If no address is provided, returns the agent's own balance.",
|
|
9
|
+
schema: z.object({
|
|
10
|
+
address: z
|
|
11
|
+
.string()
|
|
12
|
+
.optional()
|
|
13
|
+
.describe("TON address to check. Leave empty for agent's own balance."),
|
|
14
|
+
}),
|
|
15
|
+
handler: async (agent, params) => {
|
|
16
|
+
const targetAddress = params.address
|
|
17
|
+
? Address.parse(params.address)
|
|
18
|
+
: agent.wallet.address;
|
|
19
|
+
|
|
20
|
+
const lastBlock = await (agent.connection as any).getLastBlock();
|
|
21
|
+
const state = await (agent.connection as any).getAccount(
|
|
22
|
+
lastBlock.last.seqno,
|
|
23
|
+
targetAddress
|
|
24
|
+
);
|
|
25
|
+
|
|
26
|
+
const balanceRaw = state.account.balance.coins.toString();
|
|
27
|
+
const balance = fromNano(state.account.balance.coins);
|
|
28
|
+
|
|
29
|
+
return {
|
|
30
|
+
balance,
|
|
31
|
+
balanceRaw,
|
|
32
|
+
address: targetAddress.toRawString(),
|
|
33
|
+
friendlyAddress: toFriendlyAddress(targetAddress, agent.network),
|
|
34
|
+
};
|
|
35
|
+
},
|
|
36
|
+
examples: [
|
|
37
|
+
{
|
|
38
|
+
input: {},
|
|
39
|
+
output: { balance: "42.5", balanceRaw: "42500000000", address: "EQ..." },
|
|
40
|
+
description: "Get agent's own balance",
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
input: { address: "EQBx2CfDE..." },
|
|
44
|
+
output: { balance: "100.0", balanceRaw: "100000000000", address: "EQBx2CfDE..." },
|
|
45
|
+
description: "Get balance of a specific address",
|
|
46
|
+
},
|
|
47
|
+
],
|
|
48
|
+
});
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { defineAction, type JettonBalanceResult } from "@ton-agent-kit/core";
|
|
3
|
+
|
|
4
|
+
export const getJettonBalanceAction = defineAction<
|
|
5
|
+
{ jettonAddress: string; ownerAddress?: string },
|
|
6
|
+
JettonBalanceResult
|
|
7
|
+
>({
|
|
8
|
+
name: "get_jetton_balance",
|
|
9
|
+
description:
|
|
10
|
+
"Get the balance of a specific Jetton (token) for a wallet. Provide the Jetton master address. If no owner is specified, checks the agent's own balance.",
|
|
11
|
+
schema: z.object({
|
|
12
|
+
jettonAddress: z.string().describe("Jetton master contract address"),
|
|
13
|
+
ownerAddress: z.string().optional().describe("Wallet address to check. Defaults to agent's own address."),
|
|
14
|
+
}),
|
|
15
|
+
handler: async (agent, params) => {
|
|
16
|
+
const ownerAddr = params.ownerAddress
|
|
17
|
+
? params.ownerAddress
|
|
18
|
+
: agent.wallet.address.toRawString();
|
|
19
|
+
|
|
20
|
+
const apiBase =
|
|
21
|
+
agent.network === "testnet"
|
|
22
|
+
? "https://testnet.tonapi.io/v2"
|
|
23
|
+
: "https://tonapi.io/v2";
|
|
24
|
+
|
|
25
|
+
const headers: Record<string, string> = {};
|
|
26
|
+
if (agent.config.TONAPI_KEY) {
|
|
27
|
+
headers["Authorization"] = `Bearer ${agent.config.TONAPI_KEY}`;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
try {
|
|
31
|
+
// Use TONAPI which handles all address formats (raw, user-friendly, etc.)
|
|
32
|
+
const response = await fetch(
|
|
33
|
+
`${apiBase}/accounts/${encodeURIComponent(ownerAddr)}/jettons/${encodeURIComponent(params.jettonAddress)}`,
|
|
34
|
+
{ headers },
|
|
35
|
+
);
|
|
36
|
+
|
|
37
|
+
if (!response.ok) {
|
|
38
|
+
return {
|
|
39
|
+
balance: "0",
|
|
40
|
+
balanceRaw: "0",
|
|
41
|
+
symbol: "JETTON",
|
|
42
|
+
name: "Jetton",
|
|
43
|
+
decimals: 9,
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const data = await response.json();
|
|
48
|
+
const decimals = data.jetton?.decimals ?? 9;
|
|
49
|
+
const balanceRaw = data.balance || "0";
|
|
50
|
+
const balance = (Number(balanceRaw) / Math.pow(10, decimals)).toString();
|
|
51
|
+
|
|
52
|
+
return {
|
|
53
|
+
balance,
|
|
54
|
+
balanceRaw,
|
|
55
|
+
symbol: data.jetton?.symbol || "JETTON",
|
|
56
|
+
name: data.jetton?.name || "Jetton",
|
|
57
|
+
decimals,
|
|
58
|
+
};
|
|
59
|
+
} catch {
|
|
60
|
+
return {
|
|
61
|
+
balance: "0",
|
|
62
|
+
balanceRaw: "0",
|
|
63
|
+
symbol: "JETTON",
|
|
64
|
+
name: "Jetton",
|
|
65
|
+
decimals: 9,
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
},
|
|
69
|
+
});
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { Address } from "@ton/core";
|
|
3
|
+
import { JettonMaster } from "@ton/ton";
|
|
4
|
+
import { defineAction, type JettonInfo, toFriendlyAddress } from "@ton-agent-kit/core";
|
|
5
|
+
|
|
6
|
+
export const getJettonInfoAction = defineAction<
|
|
7
|
+
{ jettonAddress: string },
|
|
8
|
+
JettonInfo
|
|
9
|
+
>({
|
|
10
|
+
name: "get_jetton_info",
|
|
11
|
+
description:
|
|
12
|
+
"Get information about a Jetton (token) including name, symbol, total supply, and admin address.",
|
|
13
|
+
schema: z.object({
|
|
14
|
+
jettonAddress: z.string().describe("Jetton master contract address"),
|
|
15
|
+
}),
|
|
16
|
+
handler: async (agent, params) => {
|
|
17
|
+
const jettonMasterAddr = Address.parse(params.jettonAddress);
|
|
18
|
+
const jettonMaster = (agent.connection as any).open(
|
|
19
|
+
JettonMaster.create(jettonMasterAddr)
|
|
20
|
+
);
|
|
21
|
+
|
|
22
|
+
const data = await jettonMaster.getJettonData();
|
|
23
|
+
|
|
24
|
+
return {
|
|
25
|
+
address: jettonMasterAddr.toRawString(),
|
|
26
|
+
friendlyAddress: toFriendlyAddress(jettonMasterAddr, agent.network),
|
|
27
|
+
name: "Unknown",
|
|
28
|
+
symbol: "???",
|
|
29
|
+
decimals: 9,
|
|
30
|
+
totalSupply: data.totalSupply.toString(),
|
|
31
|
+
};
|
|
32
|
+
},
|
|
33
|
+
});
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { Address, toNano, beginCell, internal } from "@ton/core";
|
|
3
|
+
import { JettonMaster, JettonWallet } from "@ton/ton";
|
|
4
|
+
import { defineAction, type TransactionResult, sendTransaction, explorerUrl, toFriendlyAddress } from "@ton-agent-kit/core";
|
|
5
|
+
|
|
6
|
+
export const transferJettonAction = defineAction<
|
|
7
|
+
{ to: string; amount: string; jettonAddress: string },
|
|
8
|
+
TransactionResult
|
|
9
|
+
>({
|
|
10
|
+
name: "transfer_jetton",
|
|
11
|
+
description:
|
|
12
|
+
"Transfer Jettons (TON tokens like USDT, NOT, etc.) to another address. Requires the Jetton master contract address.",
|
|
13
|
+
schema: z.object({
|
|
14
|
+
to: z.string().describe("Destination address"),
|
|
15
|
+
amount: z.string().describe("Amount to send in token units (e.g., '100')"),
|
|
16
|
+
jettonAddress: z
|
|
17
|
+
.string()
|
|
18
|
+
.describe("Jetton master contract address (e.g., USDT address on TON)"),
|
|
19
|
+
}),
|
|
20
|
+
handler: async (agent, params) => {
|
|
21
|
+
const toAddress = Address.parse(params.to);
|
|
22
|
+
const jettonMasterAddress = Address.parse(params.jettonAddress);
|
|
23
|
+
|
|
24
|
+
// Get the sender's Jetton wallet address
|
|
25
|
+
const jettonMaster = agent.connection.open(
|
|
26
|
+
JettonMaster.create(jettonMasterAddress)
|
|
27
|
+
) as any;
|
|
28
|
+
|
|
29
|
+
const jettonWalletAddress = await jettonMaster.getWalletAddress(
|
|
30
|
+
agent.wallet.address
|
|
31
|
+
);
|
|
32
|
+
|
|
33
|
+
// Build transfer message
|
|
34
|
+
const forwardPayload = beginCell().storeUint(0, 32).storeStringTail("").endCell();
|
|
35
|
+
|
|
36
|
+
const transferBody = beginCell()
|
|
37
|
+
.storeUint(0xf8a7ea5, 32) // transfer op
|
|
38
|
+
.storeUint(0, 64) // query_id
|
|
39
|
+
.storeCoins(BigInt(Math.floor(parseFloat(params.amount) * 1e9))) // amount in raw units (assuming 9 decimals)
|
|
40
|
+
.storeAddress(toAddress) // destination
|
|
41
|
+
.storeAddress(agent.wallet.address) // response destination
|
|
42
|
+
.storeBit(0) // no custom payload
|
|
43
|
+
.storeCoins(toNano("0.01")) // forward TON amount
|
|
44
|
+
.storeBit(1) // forward payload
|
|
45
|
+
.storeRef(forwardPayload)
|
|
46
|
+
.endCell();
|
|
47
|
+
|
|
48
|
+
await sendTransaction(agent, [
|
|
49
|
+
internal({
|
|
50
|
+
to: jettonWalletAddress,
|
|
51
|
+
value: toNano("0.05"),
|
|
52
|
+
bounce: true,
|
|
53
|
+
body: transferBody,
|
|
54
|
+
}),
|
|
55
|
+
]);
|
|
56
|
+
|
|
57
|
+
return {
|
|
58
|
+
txHash: "pending",
|
|
59
|
+
status: "sent",
|
|
60
|
+
to: params.to,
|
|
61
|
+
friendlyTo: toFriendlyAddress(toAddress, agent.network),
|
|
62
|
+
explorerUrl: explorerUrl("pending", agent.network),
|
|
63
|
+
fee: "~0.037 TON",
|
|
64
|
+
};
|
|
65
|
+
},
|
|
66
|
+
examples: [
|
|
67
|
+
{
|
|
68
|
+
input: {
|
|
69
|
+
to: "EQBx2...",
|
|
70
|
+
amount: "100",
|
|
71
|
+
jettonAddress: "EQCxE6mUtQJKFnGfaROTKOt1lZbDiiX1kCixRv7Nw2Id_sDs",
|
|
72
|
+
},
|
|
73
|
+
output: { txHash: "abc123", status: "sent", fee: "~0.037 TON" },
|
|
74
|
+
description: "Send 100 USDT to an address",
|
|
75
|
+
},
|
|
76
|
+
],
|
|
77
|
+
});
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { Address, toNano, fromNano, internal } from "@ton/core";
|
|
3
|
+
import { defineAction, type TransactionResult, explorerUrl, sendTransaction, toFriendlyAddress } from "@ton-agent-kit/core";
|
|
4
|
+
|
|
5
|
+
export const transferTonAction = defineAction<
|
|
6
|
+
{ to: string; amount: string; comment?: string },
|
|
7
|
+
TransactionResult
|
|
8
|
+
>({
|
|
9
|
+
name: "transfer_ton",
|
|
10
|
+
description:
|
|
11
|
+
"Transfer TON to another wallet address. Specify the destination address and amount in TON (e.g., '1.5').",
|
|
12
|
+
schema: z.object({
|
|
13
|
+
to: z.string().describe("Destination TON address (raw or user-friendly format)"),
|
|
14
|
+
amount: z.string().describe("Amount of TON to send (e.g., '1.5', '100')"),
|
|
15
|
+
comment: z.string().optional().describe("Optional comment to include in the transfer"),
|
|
16
|
+
}),
|
|
17
|
+
handler: async (agent, params) => {
|
|
18
|
+
const toAddress = Address.parse(params.to);
|
|
19
|
+
const amountNano = toNano(params.amount);
|
|
20
|
+
|
|
21
|
+
// Validate amount
|
|
22
|
+
if (amountNano <= 0n) {
|
|
23
|
+
throw new Error("Amount must be greater than 0");
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// Check balance before sending
|
|
27
|
+
const lastBlock = await (agent.connection as any).getLastBlock();
|
|
28
|
+
const accountState = await (agent.connection as any).getAccount(
|
|
29
|
+
lastBlock.last.seqno,
|
|
30
|
+
agent.wallet.address,
|
|
31
|
+
);
|
|
32
|
+
const balanceNano = accountState.account.balance.coins;
|
|
33
|
+
if (amountNano > balanceNano) {
|
|
34
|
+
throw new Error(
|
|
35
|
+
`Insufficient balance: have ${fromNano(balanceNano)} TON, need ${params.amount} TON`,
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Build and send the internal message using proven V5R1 pattern
|
|
40
|
+
await sendTransaction(agent, [
|
|
41
|
+
internal({
|
|
42
|
+
to: toAddress,
|
|
43
|
+
value: amountNano,
|
|
44
|
+
bounce: false,
|
|
45
|
+
body: params.comment ? buildCommentBody(params.comment) : undefined,
|
|
46
|
+
}),
|
|
47
|
+
]);
|
|
48
|
+
|
|
49
|
+
return {
|
|
50
|
+
txHash: "pending",
|
|
51
|
+
status: "sent",
|
|
52
|
+
to: params.to,
|
|
53
|
+
friendlyTo: toFriendlyAddress(toAddress, agent.network),
|
|
54
|
+
explorerUrl: explorerUrl("pending", agent.network),
|
|
55
|
+
fee: "~0.005 TON",
|
|
56
|
+
};
|
|
57
|
+
},
|
|
58
|
+
examples: [
|
|
59
|
+
{
|
|
60
|
+
input: { to: "EQBx2CfDE...", amount: "5" },
|
|
61
|
+
output: { txHash: "abc123", status: "sent", fee: "~0.005 TON" },
|
|
62
|
+
description: "Send 5 TON to an address",
|
|
63
|
+
},
|
|
64
|
+
],
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Build a comment body Cell for simple text transfers
|
|
69
|
+
*/
|
|
70
|
+
function buildCommentBody(comment: string) {
|
|
71
|
+
const { beginCell } = require("@ton/core");
|
|
72
|
+
return beginCell()
|
|
73
|
+
.storeUint(0, 32) // 0 opcode = text comment
|
|
74
|
+
.storeStringTail(comment)
|
|
75
|
+
.endCell();
|
|
76
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { definePlugin } from "@ton-agent-kit/core";
|
|
2
|
+
import { getBalanceAction } from "./actions/get-balance";
|
|
3
|
+
import { transferTonAction } from "./actions/transfer-ton";
|
|
4
|
+
import { transferJettonAction } from "./actions/transfer-jetton";
|
|
5
|
+
import { getJettonBalanceAction } from "./actions/get-jetton-balance";
|
|
6
|
+
import { deployJettonAction } from "./actions/deploy-jetton";
|
|
7
|
+
import { getJettonInfoAction } from "./actions/get-jetton-info";
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Token Plugin — TON and Jetton operations
|
|
11
|
+
*
|
|
12
|
+
* Actions:
|
|
13
|
+
* - get_balance: Get TON balance
|
|
14
|
+
* - get_jetton_balance: Get Jetton token balance
|
|
15
|
+
* - transfer_ton: Send TON
|
|
16
|
+
* - transfer_jetton: Send Jettons
|
|
17
|
+
* - deploy_jetton: Deploy a new token
|
|
18
|
+
* - get_jetton_info: Get token metadata
|
|
19
|
+
*/
|
|
20
|
+
const TokenPlugin = definePlugin({
|
|
21
|
+
name: "token",
|
|
22
|
+
actions: [
|
|
23
|
+
getBalanceAction,
|
|
24
|
+
getJettonBalanceAction,
|
|
25
|
+
transferTonAction,
|
|
26
|
+
transferJettonAction,
|
|
27
|
+
deployJettonAction,
|
|
28
|
+
getJettonInfoAction,
|
|
29
|
+
],
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
export default TokenPlugin;
|
|
33
|
+
|
|
34
|
+
// Also export individual actions for selective use
|
|
35
|
+
export {
|
|
36
|
+
getBalanceAction,
|
|
37
|
+
getJettonBalanceAction,
|
|
38
|
+
transferTonAction,
|
|
39
|
+
transferJettonAction,
|
|
40
|
+
deployJettonAction,
|
|
41
|
+
getJettonInfoAction,
|
|
42
|
+
};
|