-
Notifications
You must be signed in to change notification settings - Fork 6
Expand file tree
/
Copy pathtron-sign-and-broadcast.ts
More file actions
138 lines (122 loc) · 5.15 KB
/
Copy pathtron-sign-and-broadcast.ts
File metadata and controls
138 lines (122 loc) · 5.15 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
/**
* Demo: Sign a TRON transaction and broadcast it using agent-wallet SDK.
*
* This example shows how mcp-server-tron (or any other integration) can use
* the agent-wallet SDK to:
* 1. Resolve a config-backed or env-backed wallet provider
* 2. Get the active wallet
* 3. Sign a message (pure local, no network)
* 4. Build an unsigned tx via TronGrid, sign it with the SDK, and broadcast
*
* The SDK is signing-only. The caller is responsible for building transactions
* (via TronGrid / TronWeb) and broadcasting them.
*
* Prerequisites:
* - Either configure a wallet via the CLI:
* agent-wallet start local_secure --wallet-id wallet-b
* agent-wallet start raw_secret --wallet-id wallet-b --mnemonic "..."
* - Or provide env fallback:
* AGENT_WALLET_PRIVATE_KEY=<hex>
* - The wallet address must be activated (have received TRX at least once)
*
* Usage:
* AGENT_WALLET_PRIVATE_KEY=<hex> npx tsx examples/tron-sign-and-broadcast.ts
*/
import { resolveWalletProvider } from '../src/index.js'
// Transfer parameters
const TO_ADDRESS = 'TUJ1C4ybdcueXbi8Wmrqscteux5eGvrCh6'
const AMOUNT_SUN = 1_000_000 // 1 TRX = 1,000,000 SUN
// TronGrid endpoints by network
const TRONGRID_URLS: Record<string, string> = {
mainnet: 'https://api.trongrid.io',
nile: 'https://nile.trongrid.io',
shasta: 'https://api.shasta.trongrid.io',
}
async function main() {
// ----------------------------------------------------------------
// Step 1: Resolve provider and active wallet
// ----------------------------------------------------------------
const provider = resolveWalletProvider({ network: 'tron', dir: '/tmp/test-wallet' })
// ----------------------------------------------------------------
// Step 2: Get wallet instance
// ----------------------------------------------------------------
const wallet = await provider.getActiveWallet()
const address = await wallet.getAddress()
console.log(`Address: ${address}`)
console.log()
// ----------------------------------------------------------------
// Step 3: Sign a message (pure local, no network)
// ----------------------------------------------------------------
const message = Buffer.from('Hello from agent-wallet!')
const msgSig = await wallet.signMessage(message)
console.log(`Message signature: ${msgSig}`)
console.log()
// ----------------------------------------------------------------
// Step 4: Build unsigned tx via TronGrid, then sign with SDK
//
// The caller builds the transaction using TronGrid's REST API.
// The SDK only signs: it takes the unsigned tx { txID, raw_data_hex }
// and returns a signed tx JSON with the signature attached.
// ----------------------------------------------------------------
const network: string = 'nile'
const baseUrl = TRONGRID_URLS[network] ?? TRONGRID_URLS['nile']
console.log(`Signing TRX transfer: ${AMOUNT_SUN} SUN -> ${TO_ADDRESS}`)
console.log(`Network: ${network} (${baseUrl})`)
// 5a. Caller builds unsigned tx via TronGrid
const unsignedTx = await buildTrxTransfer(baseUrl, address, TO_ADDRESS, AMOUNT_SUN)
console.log(`TX ID: ${unsignedTx.txID}`)
console.log(`Unsigned TX: ${JSON.stringify(unsignedTx)}`)
// 5b. SDK signs the unsigned tx
const signedTxJson = await wallet.signTransaction(unsignedTx)
const signedTx = JSON.parse(signedTxJson) as Record<string, unknown>
console.log(`Signature: ${(signedTx.signature as string[])[0]}`)
console.log(`Raw SignedTx: ${JSON.stringify(signedTx)}`)
// ----------------------------------------------------------------
// Step 5: Caller broadcasts the signed tx
// ----------------------------------------------------------------
console.log('Broadcasting...')
const txid = await broadcastTransaction(signedTx, baseUrl)
console.log(`Broadcasted! txid: ${txid}`)
const explorerBase =
network === 'mainnet' ? 'https://tronscan.org' : `https://${network}.tronscan.org`
console.log(`Explorer: ${explorerBase}/#/transaction/${txid}`)
}
// --- Helper functions (caller's responsibility, NOT part of SDK) ---
async function buildTrxTransfer(
baseUrl: string,
from: string,
to: string,
amountSun: number,
): Promise<Record<string, unknown>> {
const res = await fetch(`${baseUrl}/wallet/createtransaction`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
owner_address: from,
to_address: to,
amount: amountSun,
visible: true,
}),
})
const tx = (await res.json()) as Record<string, unknown>
if (!tx.txID) {
throw new Error(`Failed to build transaction: ${JSON.stringify(tx)}`)
}
return tx
}
async function broadcastTransaction(
signedTx: Record<string, unknown>,
baseUrl: string,
): Promise<string> {
const res = await fetch(`${baseUrl}/wallet/broadcasttransaction`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(signedTx),
})
const result = (await res.json()) as Record<string, unknown>
if (result.result) {
return (result.txid as string) ?? (signedTx.txID as string) ?? ''
}
throw new Error(`Broadcast rejected: ${JSON.stringify(result)}`)
}
main().catch(console.error)