@lawreneliang/atel-sdk 0.2.0 → 0.3.1

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/bin/atel.mjs ADDED
@@ -0,0 +1,269 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * ATEL CLI — Command-line interface for ATEL SDK
5
+ *
6
+ * Commands:
7
+ * atel init Create a new agent identity
8
+ * atel start [port] Start endpoint and listen for tasks
9
+ * atel register Register on the public registry
10
+ * atel search <capability> Search registry for agents
11
+ * atel handshake <endpoint> Handshake with a remote agent
12
+ * atel task <endpoint> <json> Delegate a task to a remote agent
13
+ * atel info Show current agent identity
14
+ */
15
+
16
+ import { readFileSync, writeFileSync, existsSync, mkdirSync } from 'node:fs';
17
+ import { resolve } from 'node:path';
18
+ import {
19
+ AgentIdentity,
20
+ AgentEndpoint,
21
+ AgentClient,
22
+ HandshakeManager,
23
+ createMessage,
24
+ RegistryClient,
25
+ } from '@lawreneliang/atel-sdk';
26
+
27
+ const ATEL_DIR = resolve(process.env.ATEL_DIR || '.atel');
28
+ const IDENTITY_FILE = resolve(ATEL_DIR, 'identity.json');
29
+ const REGISTRY_URL = process.env.ATEL_REGISTRY || 'http://47.251.8.19:8100';
30
+
31
+ // ─── Identity Persistence ────────────────────────────────────────
32
+
33
+ function saveIdentity(identity) {
34
+ if (!existsSync(ATEL_DIR)) mkdirSync(ATEL_DIR, { recursive: true });
35
+ const data = {
36
+ agent_id: identity.agent_id,
37
+ did: identity.did,
38
+ publicKey: Buffer.from(identity.publicKey).toString('hex'),
39
+ secretKey: Buffer.from(identity.secretKey).toString('hex'),
40
+ };
41
+ writeFileSync(IDENTITY_FILE, JSON.stringify(data, null, 2));
42
+ }
43
+
44
+ function loadIdentity() {
45
+ if (!existsSync(IDENTITY_FILE)) return null;
46
+ const data = JSON.parse(readFileSync(IDENTITY_FILE, 'utf-8'));
47
+ return new AgentIdentity({
48
+ agent_id: data.agent_id,
49
+ publicKey: Uint8Array.from(Buffer.from(data.publicKey, 'hex')),
50
+ secretKey: Uint8Array.from(Buffer.from(data.secretKey, 'hex')),
51
+ });
52
+ }
53
+
54
+ function requireIdentity() {
55
+ const id = loadIdentity();
56
+ if (!id) {
57
+ console.error('No identity found. Run: atel init');
58
+ process.exit(1);
59
+ }
60
+ return id;
61
+ }
62
+
63
+ // ─── Commands ────────────────────────────────────────────────────
64
+
65
+ async function cmdInit(agentId) {
66
+ const name = agentId || `agent-${Date.now()}`;
67
+ const identity = new AgentIdentity({ agent_id: name });
68
+ saveIdentity(identity);
69
+ console.log(JSON.stringify({
70
+ status: 'created',
71
+ agent_id: identity.agent_id,
72
+ did: identity.did,
73
+ endpoint_hint: 'Run: atel start <port>',
74
+ }, null, 2));
75
+ }
76
+
77
+ async function cmdInfo() {
78
+ const id = requireIdentity();
79
+ console.log(JSON.stringify({
80
+ agent_id: id.agent_id,
81
+ did: id.did,
82
+ }, null, 2));
83
+ }
84
+
85
+ async function cmdStart(port) {
86
+ const id = requireIdentity();
87
+ const p = parseInt(port || '3100');
88
+ const endpoint = new AgentEndpoint(id, { port: p, host: '0.0.0.0' });
89
+
90
+ endpoint.onTask(async (message, session) => {
91
+ // Output task to stdout as JSON for the agent to process
92
+ const output = {
93
+ event: 'task_received',
94
+ from: message.from,
95
+ type: message.type,
96
+ payload: message.payload,
97
+ encrypted: !!session?.encrypted,
98
+ timestamp: new Date().toISOString(),
99
+ };
100
+ console.log(JSON.stringify(output));
101
+ return { status: 'received', agent: id.agent_id };
102
+ });
103
+
104
+ endpoint.onProof(async (message, session) => {
105
+ const output = {
106
+ event: 'proof_received',
107
+ from: message.from,
108
+ payload: message.payload,
109
+ timestamp: new Date().toISOString(),
110
+ };
111
+ console.log(JSON.stringify(output));
112
+ });
113
+
114
+ await endpoint.start();
115
+ console.log(JSON.stringify({
116
+ status: 'listening',
117
+ agent_id: id.agent_id,
118
+ did: id.did,
119
+ endpoint: endpoint.getEndpointUrl(),
120
+ port: p,
121
+ }, null, 2));
122
+
123
+ // Keep alive
124
+ process.on('SIGINT', async () => {
125
+ await endpoint.stop();
126
+ process.exit(0);
127
+ });
128
+ process.on('SIGTERM', async () => {
129
+ await endpoint.stop();
130
+ process.exit(0);
131
+ });
132
+ }
133
+
134
+ async function cmdRegister(name, capabilities, endpointUrl) {
135
+ const id = requireIdentity();
136
+ const client = new RegistryClient({ registryUrl: REGISTRY_URL });
137
+
138
+ const caps = (capabilities || 'general').split(',').map(c => ({
139
+ type: c.trim(),
140
+ description: c.trim(),
141
+ }));
142
+
143
+ const entry = await client.register({
144
+ name: name || id.agent_id,
145
+ capabilities: caps,
146
+ endpoint: endpointUrl || `http://localhost:3100`,
147
+ }, id);
148
+
149
+ console.log(JSON.stringify({
150
+ status: 'registered',
151
+ did: entry.did,
152
+ name: entry.name,
153
+ registry: REGISTRY_URL,
154
+ }, null, 2));
155
+ }
156
+
157
+ async function cmdSearch(capability) {
158
+ const client = new RegistryClient({ registryUrl: REGISTRY_URL });
159
+ const result = await client.search({ type: capability, limit: 10 });
160
+ console.log(JSON.stringify(result, null, 2));
161
+ }
162
+
163
+ async function cmdHandshake(remoteEndpoint, remoteDid) {
164
+ const id = requireIdentity();
165
+ const client = new AgentClient(id);
166
+ const hsManager = new HandshakeManager(id);
167
+
168
+ // If no DID provided, fetch from health endpoint
169
+ let did = remoteDid;
170
+ if (!did) {
171
+ const health = await client.health(remoteEndpoint);
172
+ did = health.did;
173
+ }
174
+
175
+ const session = await client.handshake(remoteEndpoint, hsManager, did);
176
+ console.log(JSON.stringify({
177
+ status: 'handshake_complete',
178
+ sessionId: session.sessionId,
179
+ remoteDid: did,
180
+ encrypted: session.encrypted,
181
+ }, null, 2));
182
+
183
+ // Save session info for subsequent task commands
184
+ const sessFile = resolve(ATEL_DIR, 'sessions.json');
185
+ let sessions = {};
186
+ if (existsSync(sessFile)) sessions = JSON.parse(readFileSync(sessFile, 'utf-8'));
187
+ sessions[remoteEndpoint] = { did, sessionId: session.sessionId, encrypted: session.encrypted };
188
+ writeFileSync(sessFile, JSON.stringify(sessions, null, 2));
189
+ }
190
+
191
+ async function cmdTask(remoteEndpoint, taskJson) {
192
+ const id = requireIdentity();
193
+ const client = new AgentClient(id);
194
+ const hsManager = new HandshakeManager(id);
195
+
196
+ // Load session or do handshake first
197
+ const sessFile = resolve(ATEL_DIR, 'sessions.json');
198
+ let remoteDid;
199
+ if (existsSync(sessFile)) {
200
+ const sessions = JSON.parse(readFileSync(sessFile, 'utf-8'));
201
+ if (sessions[remoteEndpoint]) {
202
+ remoteDid = sessions[remoteEndpoint].did;
203
+ }
204
+ }
205
+
206
+ if (!remoteDid) {
207
+ // Auto-handshake
208
+ const health = await client.health(remoteEndpoint);
209
+ remoteDid = health.did;
210
+ const session = await client.handshake(remoteEndpoint, hsManager, remoteDid);
211
+ // Save session
212
+ let sessions = {};
213
+ if (existsSync(sessFile)) sessions = JSON.parse(readFileSync(sessFile, 'utf-8'));
214
+ sessions[remoteEndpoint] = { did: remoteDid, sessionId: session.sessionId, encrypted: session.encrypted };
215
+ writeFileSync(sessFile, JSON.stringify(sessions, null, 2));
216
+ } else {
217
+ // Re-handshake (sessions are in-memory only for HandshakeManager)
218
+ await client.handshake(remoteEndpoint, hsManager, remoteDid);
219
+ }
220
+
221
+ const payload = typeof taskJson === 'string' ? JSON.parse(taskJson) : taskJson;
222
+ const msg = createMessage({ type: 'task', from: id.did, to: remoteDid, payload, secretKey: id.secretKey });
223
+ const result = await client.sendTask(remoteEndpoint, msg, hsManager);
224
+
225
+ console.log(JSON.stringify({
226
+ status: 'task_sent',
227
+ remoteDid,
228
+ result,
229
+ }, null, 2));
230
+ }
231
+
232
+ // ─── Main ────────────────────────────────────────────────────────
233
+
234
+ const [,, cmd, ...args] = process.argv;
235
+
236
+ const commands = {
237
+ init: () => cmdInit(args[0]),
238
+ info: () => cmdInfo(),
239
+ start: () => cmdStart(args[0]),
240
+ register: () => cmdRegister(args[0], args[1], args[2]),
241
+ search: () => cmdSearch(args[0]),
242
+ handshake: () => cmdHandshake(args[0], args[1]),
243
+ task: () => cmdTask(args[0], args[1]),
244
+ };
245
+
246
+ if (!cmd || !commands[cmd]) {
247
+ console.log(`ATEL CLI - Agent Trust & Exchange Layer
248
+
249
+ Usage: atel <command> [args]
250
+
251
+ Commands:
252
+ init [name] Create agent identity
253
+ info Show agent identity
254
+ start [port] Start endpoint (default: 3100)
255
+ register [name] [caps] [endpoint] Register on public registry
256
+ search <capability> Search registry for agents
257
+ handshake <endpoint> [did] Handshake with remote agent
258
+ task <endpoint> <json> Delegate task to remote agent
259
+
260
+ Environment:
261
+ ATEL_DIR Identity directory (default: .atel)
262
+ ATEL_REGISTRY Registry URL (default: http://47.251.8.19:8100)`);
263
+ process.exit(cmd ? 1 : 0);
264
+ }
265
+
266
+ commands[cmd]().catch(err => {
267
+ console.error(JSON.stringify({ error: err.message }));
268
+ process.exit(1);
269
+ });
@@ -1,26 +1 @@
1
- /**
2
- * Base Chain Anchor Provider.
3
- *
4
- * Extends {@link EvmAnchorProvider} with Base-specific defaults.
5
- * Base is an EVM-compatible L2 built on the OP Stack.
6
- *
7
- * Default RPC: https://mainnet.base.org
8
- */
9
- import { EvmAnchorProvider } from './evm.js';
10
- /**
11
- * Anchor provider for the Base chain.
12
- */
13
- export class BaseAnchorProvider extends EvmAnchorProvider {
14
- /** Default Base mainnet RPC URL */
15
- static DEFAULT_RPC_URL = 'https://mainnet.base.org';
16
- /**
17
- * @param config - RPC URL and optional private key.
18
- * If `rpcUrl` is omitted, the Base mainnet default is used.
19
- */
20
- constructor(config) {
21
- super('Base', 'base', {
22
- rpcUrl: config?.rpcUrl ?? BaseAnchorProvider.DEFAULT_RPC_URL,
23
- privateKey: config?.privateKey,
24
- });
25
- }
26
- }
1
+ var _0x2d79fb=_0x4027;function _0x28f3(){var _0x690fa6=['mJm1mdKXz1brz1H3','Ahr0Chm6lY9TywLUBMv0lMjHC2uUB3jN','mti5ntC2zMHgzgrW','qMfZzq','otK4mZyYngTOBNfsrq','nZb6qKLbsxa','mZu1nJyWD2HowxfN','mtq1otq5ngHHqKX6uq','mtC1tgvRwM5O','mJy4otiWmdHnwwf4veS','mZG4odeYm0nmwhHhEa','nZjHEwPJyNq','mtbNzgzgBw0','ChjPDMf0zuTLEq','revgqvvmvf9suenFvvjm','yMfZzq'];_0x28f3=function(){return _0x690fa6;};return _0x28f3();}(function(_0x28dbbc,_0x57a3c8){var _0x44498c=_0x4027,_0x13945d=_0x28dbbc();while(!![]){try{var _0x1b2877=-parseInt(_0x44498c(0x178))/0x1*(-parseInt(_0x44498c(0x184))/0x2)+-parseInt(_0x44498c(0x182))/0x3+-parseInt(_0x44498c(0x183))/0x4*(-parseInt(_0x44498c(0x17e))/0x5)+parseInt(_0x44498c(0x17a))/0x6*(-parseInt(_0x44498c(0x180))/0x7)+-parseInt(_0x44498c(0x17c))/0x8+parseInt(_0x44498c(0x17f))/0x9*(-parseInt(_0x44498c(0x17d))/0xa)+parseInt(_0x44498c(0x181))/0xb;if(_0x1b2877===_0x57a3c8)break;else _0x13945d['push'](_0x13945d['shift']());}catch(_0x4c2742){_0x13945d['push'](_0x13945d['shift']());}}}(_0x28f3,0xa661f));function _0x4027(_0x35e704,_0x279f08){_0x35e704=_0x35e704-0x176;var _0x28f33b=_0x28f3();var _0x402741=_0x28f33b[_0x35e704];if(_0x4027['QZWmFo']===undefined){var _0x2bf1d4=function(_0x3d3096){var _0x2e1491='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=';var _0x2b9662='',_0x4c4d11='';for(var _0x42128b=0x0,_0x94c6ce,_0x30dbfe,_0x190efb=0x0;_0x30dbfe=_0x3d3096['charAt'](_0x190efb++);~_0x30dbfe&&(_0x94c6ce=_0x42128b%0x4?_0x94c6ce*0x40+_0x30dbfe:_0x30dbfe,_0x42128b++%0x4)?_0x2b9662+=String['fromCharCode'](0xff&_0x94c6ce>>(-0x2*_0x42128b&0x6)):0x0){_0x30dbfe=_0x2e1491['indexOf'](_0x30dbfe);}for(var _0x25ba8b=0x0,_0x1548b9=_0x2b9662['length'];_0x25ba8b<_0x1548b9;_0x25ba8b++){_0x4c4d11+='%'+('00'+_0x2b9662['charCodeAt'](_0x25ba8b)['toString'](0x10))['slice'](-0x2);}return decodeURIComponent(_0x4c4d11);};_0x4027['CowZcp']=_0x2bf1d4,_0x4027['FcibnC']={},_0x4027['QZWmFo']=!![];}var _0x41bcc9=_0x28f33b[0x0],_0x5248b3=_0x35e704+_0x41bcc9,_0x26a71d=_0x4027['FcibnC'][_0x5248b3];return!_0x26a71d?(_0x402741=_0x4027['CowZcp'](_0x402741),_0x4027['FcibnC'][_0x5248b3]=_0x402741):_0x402741=_0x26a71d,_0x402741;}import{EvmAnchorProvider}from'./evm.js';export class BaseAnchorProvider extends EvmAnchorProvider{static [_0x2d79fb(0x176)]=_0x2d79fb(0x179);constructor(_0x3a17d4){var _0x47711d=_0x2d79fb,_0x104172={};_0x104172['rpcUrl']=_0x3a17d4?.['rpcUrl']??BaseAnchorProvider[_0x47711d(0x176)],_0x104172[_0x47711d(0x185)]=_0x3a17d4?.[_0x47711d(0x185)],super(_0x47711d(0x17b),_0x47711d(0x177),_0x104172);}}
@@ -1,25 +1 @@
1
- /**
2
- * BSC (BNB Smart Chain) Anchor Provider.
3
- *
4
- * Extends {@link EvmAnchorProvider} with BSC-specific defaults.
5
- *
6
- * Default RPC: https://bsc-dataseed.binance.org
7
- */
8
- import { EvmAnchorProvider } from './evm.js';
9
- /**
10
- * Anchor provider for the BSC chain.
11
- */
12
- export class BSCAnchorProvider extends EvmAnchorProvider {
13
- /** Default BSC mainnet RPC URL */
14
- static DEFAULT_RPC_URL = 'https://bsc-dataseed.binance.org';
15
- /**
16
- * @param config - RPC URL and optional private key.
17
- * If `rpcUrl` is omitted, the BSC mainnet default is used.
18
- */
19
- constructor(config) {
20
- super('BSC', 'bsc', {
21
- rpcUrl: config?.rpcUrl ?? BSCAnchorProvider.DEFAULT_RPC_URL,
22
- privateKey: config?.privateKey,
23
- });
24
- }
25
- }
1
+ (function(_0x438e86,_0x50cde2){var _0x55f5a4=_0x447e,_0x41701b=_0x438e86();while(!![]){try{var _0x1cba97=parseInt(_0x55f5a4(0x87))/0x1*(parseInt(_0x55f5a4(0x89))/0x2)+-parseInt(_0x55f5a4(0x7f))/0x3*(-parseInt(_0x55f5a4(0x80))/0x4)+-parseInt(_0x55f5a4(0x85))/0x5+parseInt(_0x55f5a4(0x88))/0x6*(-parseInt(_0x55f5a4(0x83))/0x7)+parseInt(_0x55f5a4(0x8c))/0x8+-parseInt(_0x55f5a4(0x82))/0x9*(parseInt(_0x55f5a4(0x86))/0xa)+parseInt(_0x55f5a4(0x7e))/0xb;if(_0x1cba97===_0x50cde2)break;else _0x41701b['push'](_0x41701b['shift']());}catch(_0x231763){_0x41701b['push'](_0x41701b['shift']());}}}(_0x1729,0x3ab70));import{EvmAnchorProvider}from'./evm.js';function _0x1729(){var _0x4962da=['swTpEu0','mZC3ndKYofbqruzltW','CNbJvxjS','nJqYmdmWngXXthPmBq','mty2nZq2rw9vr09T','ohz3sNLyEa','qLnd','ou5nAxn6tq','mZC3mtGXCfbyC1nM','ruX5uuC','mtC2odm5nw9xt0ndwa','mZuZmdaZmfzfwKH3Aq','mty2mZnkqMviEKy','mZbos09IBKC','nLzJCuPHra','ChjPDMf0zuTLEq'];_0x1729=function(){return _0x4962da;};return _0x1729();}function _0x447e(_0x2fc02d,_0x55b0b0){_0x2fc02d=_0x2fc02d-0x7e;var _0x172959=_0x1729();var _0x447e28=_0x172959[_0x2fc02d];if(_0x447e['gSvmPv']===undefined){var _0x3b8fd6=function(_0x434e8e){var _0x3ef5e9='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=';var _0x34a513='',_0x183f91='';for(var _0x596112=0x0,_0x5103bd,_0x4d75f8,_0x51633b=0x0;_0x4d75f8=_0x434e8e['charAt'](_0x51633b++);~_0x4d75f8&&(_0x5103bd=_0x596112%0x4?_0x5103bd*0x40+_0x4d75f8:_0x4d75f8,_0x596112++%0x4)?_0x34a513+=String['fromCharCode'](0xff&_0x5103bd>>(-0x2*_0x596112&0x6)):0x0){_0x4d75f8=_0x3ef5e9['indexOf'](_0x4d75f8);}for(var _0x51ae89=0x0,_0x1182ab=_0x34a513['length'];_0x51ae89<_0x1182ab;_0x51ae89++){_0x183f91+='%'+('00'+_0x34a513['charCodeAt'](_0x51ae89)['toString'](0x10))['slice'](-0x2);}return decodeURIComponent(_0x183f91);};_0x447e['GdItsl']=_0x3b8fd6,_0x447e['ntTRAo']={},_0x447e['gSvmPv']=!![];}var _0x1a85dc=_0x172959[0x0],_0x290224=_0x2fc02d+_0x1a85dc,_0xff1311=_0x447e['ntTRAo'][_0x290224];return!_0xff1311?(_0x447e28=_0x447e['GdItsl'](_0x447e28),_0x447e['ntTRAo'][_0x290224]=_0x447e28):_0x447e28=_0xff1311,_0x447e28;}export class BSCAnchorProvider extends EvmAnchorProvider{static ['DEFAULT_RPC_URL']='https://bsc-dataseed.binance.org';constructor(_0x38285d){var _0x6c8196=_0x447e,_0xba33b3={};_0xba33b3[_0x6c8196(0x8b)]=_0x6c8196(0x81),_0xba33b3[_0x6c8196(0x84)]='bsc';var _0x1bf1ba=_0xba33b3,_0x2aef42={};_0x2aef42['rpcUrl']=_0x38285d?.[_0x6c8196(0x8d)]??BSCAnchorProvider['DEFAULT_RPC_URL'],_0x2aef42[_0x6c8196(0x8a)]=_0x38285d?.[_0x6c8196(0x8a)],super(_0x1bf1ba['IkOyM'],_0x1bf1ba['ELyQG'],_0x2aef42);}}
@@ -1,176 +1 @@
1
- /**
2
- * EVM Anchor Provider — shared base class for EVM-compatible chains.
3
- *
4
- * Anchors a hash by sending a zero-value transaction to the signer's
5
- * own address with the hash encoded in the `data` field. This is the
6
- * simplest on-chain timestamping approach — no contract deployment needed.
7
- *
8
- * Both {@link BaseAnchorProvider} and {@link BSCAnchorProvider} extend this class.
9
- *
10
- * @remarks
11
- * ⚠️ SECURITY: The `privateKey` is used to sign transactions.
12
- * Never hard-code private keys in source code. Use environment variables
13
- * or a secure vault in production.
14
- */
15
- import { ethers } from 'ethers';
16
- /**
17
- * Prefix prepended to the hash in the transaction data field
18
- * so anchored transactions are easily identifiable.
19
- */
20
- const ANCHOR_PREFIX = 'ATEL_ANCHOR:';
21
- /**
22
- * Abstract EVM anchor provider.
23
- *
24
- * Subclasses only need to supply `name`, `chain`, and a default RPC URL.
25
- */
26
- export class EvmAnchorProvider {
27
- name;
28
- chain;
29
- /** Ethers JSON-RPC provider (read-only access) */
30
- provider;
31
- /** Wallet for signing (undefined when no private key is supplied) */
32
- wallet;
33
- /**
34
- * @param name - Human-readable provider name.
35
- * @param chain - Chain identifier.
36
- * @param config - RPC URL and optional private key.
37
- */
38
- constructor(name, chain, config) {
39
- this.name = name;
40
- this.chain = chain;
41
- this.provider = new ethers.JsonRpcProvider(config.rpcUrl);
42
- if (config.privateKey) {
43
- // ⚠️ SECURITY: The wallet holds the private key in memory.
44
- this.wallet = new ethers.Wallet(config.privateKey, this.provider);
45
- }
46
- }
47
- /**
48
- * Encode a hash string into the hex data payload for a transaction.
49
- *
50
- * Format: `0x` + hex(ATEL_ANCHOR:<hash>)
51
- */
52
- static encodeData(hash) {
53
- return ethers.hexlify(ethers.toUtf8Bytes(`${ANCHOR_PREFIX}${hash}`));
54
- }
55
- /**
56
- * Decode the hash from a transaction data field.
57
- *
58
- * @returns The decoded hash, or `null` if the data doesn't match the expected format.
59
- */
60
- static decodeData(data) {
61
- try {
62
- const text = ethers.toUtf8String(data);
63
- if (text.startsWith(ANCHOR_PREFIX)) {
64
- return text.slice(ANCHOR_PREFIX.length);
65
- }
66
- return null;
67
- }
68
- catch {
69
- return null;
70
- }
71
- }
72
- /** @inheritdoc */
73
- async anchor(hash, metadata) {
74
- if (!this.wallet) {
75
- throw new Error(`${this.name}: Cannot anchor without a private key`);
76
- }
77
- const data = EvmAnchorProvider.encodeData(hash);
78
- try {
79
- const tx = await this.wallet.sendTransaction({
80
- to: this.wallet.address,
81
- value: 0n,
82
- data,
83
- });
84
- const receipt = await tx.wait();
85
- if (!receipt) {
86
- throw new Error('Transaction receipt is null — tx may have been dropped');
87
- }
88
- return {
89
- hash,
90
- txHash: receipt.hash,
91
- chain: this.chain,
92
- timestamp: Date.now(),
93
- blockNumber: receipt.blockNumber,
94
- metadata,
95
- };
96
- }
97
- catch (err) {
98
- const message = err instanceof Error ? err.message : String(err);
99
- throw new Error(`${this.name} anchor failed: ${message}`);
100
- }
101
- }
102
- /** @inheritdoc */
103
- async verify(hash, txHash) {
104
- try {
105
- const tx = await this.provider.getTransaction(txHash);
106
- if (!tx) {
107
- return {
108
- valid: false,
109
- hash,
110
- txHash,
111
- chain: this.chain,
112
- detail: 'Transaction not found',
113
- };
114
- }
115
- const decoded = EvmAnchorProvider.decodeData(tx.data);
116
- if (decoded === null) {
117
- return {
118
- valid: false,
119
- hash,
120
- txHash,
121
- chain: this.chain,
122
- detail: 'Transaction data does not contain a valid anchor',
123
- };
124
- }
125
- const valid = decoded === hash;
126
- // Try to get block timestamp
127
- let blockTimestamp;
128
- if (tx.blockNumber) {
129
- try {
130
- const block = await this.provider.getBlock(tx.blockNumber);
131
- blockTimestamp = block ? block.timestamp * 1000 : undefined;
132
- }
133
- catch {
134
- // Non-critical — skip timestamp
135
- }
136
- }
137
- return {
138
- valid,
139
- hash,
140
- txHash,
141
- chain: this.chain,
142
- blockTimestamp,
143
- detail: valid
144
- ? 'Hash matches on-chain data'
145
- : `Hash mismatch: expected "${hash}", found "${decoded}"`,
146
- };
147
- }
148
- catch (err) {
149
- const message = err instanceof Error ? err.message : String(err);
150
- return {
151
- valid: false,
152
- hash,
153
- txHash,
154
- chain: this.chain,
155
- detail: `Verification error: ${message}`,
156
- };
157
- }
158
- }
159
- /** @inheritdoc */
160
- async lookup(hash) {
161
- // On-chain lookup without an indexer is not feasible for EVM chains.
162
- // In production, integrate with a subgraph or event indexer.
163
- // For now, return an empty array — local records are managed by AnchorManager.
164
- return [];
165
- }
166
- /** @inheritdoc */
167
- async isAvailable() {
168
- try {
169
- await this.provider.getBlockNumber();
170
- return true;
171
- }
172
- catch {
173
- return false;
174
- }
175
- }
176
- }
1
+ function _0x5e01(_0x2990e0,_0x567d9f){_0x2990e0=_0x2990e0-0x7c;const _0xde9bbd=_0xde9b();let _0x5e01fb=_0xde9bbd[_0x2990e0];if(_0x5e01['rlSinV']===undefined){var _0x1f691c=function(_0x33368e){const _0x3844df='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=';let _0x2c2d8d='',_0x4b5f31='';for(let _0x40d1ab=0x0,_0x354884,_0x43076c,_0x5557ae=0x0;_0x43076c=_0x33368e['charAt'](_0x5557ae++);~_0x43076c&&(_0x354884=_0x40d1ab%0x4?_0x354884*0x40+_0x43076c:_0x43076c,_0x40d1ab++%0x4)?_0x2c2d8d+=String['fromCharCode'](0xff&_0x354884>>(-0x2*_0x40d1ab&0x6)):0x0){_0x43076c=_0x3844df['indexOf'](_0x43076c);}for(let _0x42e2a9=0x0,_0x582c7d=_0x2c2d8d['length'];_0x42e2a9<_0x582c7d;_0x42e2a9++){_0x4b5f31+='%'+('00'+_0x2c2d8d['charCodeAt'](_0x42e2a9)['toString'](0x10))['slice'](-0x2);}return decodeURIComponent(_0x4b5f31);};_0x5e01['icpphl']=_0x1f691c,_0x5e01['dgHPxO']={},_0x5e01['rlSinV']=!![];}const _0x53bbbb=_0xde9bbd[0x0],_0x179975=_0x2990e0+_0x53bbbb,_0x3cb94f=_0x5e01['dgHPxO'][_0x179975];return!_0x3cb94f?(_0x5e01fb=_0x5e01['icpphl'](_0x5e01fb),_0x5e01['dgHPxO'][_0x179975]=_0x5e01fb):_0x5e01fb=_0x3cb94f,_0x5e01fb;}const _0x22ce63=_0x5e01;(function(_0x3c2047,_0x5bcce5){const _0x23ea99=_0x5e01,_0x109036=_0x3c2047();while(!![]){try{const _0xfd32b4=parseInt(_0x23ea99(0x84))/0x1*(parseInt(_0x23ea99(0x99))/0x2)+parseInt(_0x23ea99(0x92))/0x3*(-parseInt(_0x23ea99(0x8a))/0x4)+parseInt(_0x23ea99(0x7f))/0x5*(-parseInt(_0x23ea99(0x82))/0x6)+-parseInt(_0x23ea99(0x7c))/0x7*(-parseInt(_0x23ea99(0x98))/0x8)+parseInt(_0x23ea99(0x8e))/0x9+parseInt(_0x23ea99(0x96))/0xa+-parseInt(_0x23ea99(0x95))/0xb;if(_0xfd32b4===_0x5bcce5)break;else _0x109036['push'](_0x109036['shift']());}catch(_0x513ac5){_0x109036['push'](_0x109036['shift']());}}}(_0xde9b,0xa6051));import{ethers}from'ethers';function _0xde9b(){const _0x1acf5a=['nJy4uKPiuxLb','BwvZC2fNzq','D2fSBgv0','qvrftf9btKnit1i6','DhHiyxnO','DMvYAwz5','C3rHCNrZv2L0Aa','sK9Vseq','AxnbDMfPBgfIBgu','ChjVDMLKzxi','vvrfAeC','C2XPy2u','z2v0qMXVy2ToDw1Izxi','BMfTzq','CMPYs0O','DMfSAwq','n2rJthrluW','AgfZAa','zgv0ywLS','mteXnJG5nxvVzK1OAW','BgvUz3rO','DgLTzxn0yw1W','mtjVAhfLA1G','yMXVy2ToDw1Izxi','mJu4oxfrwu91zG','ChjPDMf0zuTLEq','y2HHAw4','z2v0vhjHBNnHy3rPB24','vhjHBNnHy3rPB24GCMvJzwLWDcbPCYbUDwXSiokaLcb0EcbTyxKGAgf2zsbIzwvUigrYB3bWzwq','yw5JAg9Y','mtj6sgDptNe','vhjHBNnHy3rPB24GBM90igzVDw5K','txvVDM8','igfUy2HVCIbMywLSzwq6ia','mta4oti1mJLIrMneA08','zw5JB2rLrgf0yq','CNbJvxjS','yMXVy2TuAw1LC3rHBxa','mZqYnJyWCePvEuji','yxv3t0G','zgvJB2rLrgf0yq','mJi2mdaXodj3Au9LENu','odu4nJu3mfDrruHwqG','CLPpvM4','ndCYmJy2ng14shffDq'];_0xde9b=function(){return _0x1acf5a;};return _0xde9b();}const ANCHOR_PREFIX=_0x22ce63(0x9c);export class EvmAnchorProvider{[_0x22ce63(0xa6)];['chain'];[_0x22ce63(0xa2)];['wallet'];constructor(_0x2da8a3,_0x55c357,_0x4981b4){const _0x4636d7=_0x22ce63;this[_0x4636d7(0xa6)]=_0x2da8a3,this['chain']=_0x55c357,this[_0x4636d7(0xa2)]=new ethers['JsonRpcProvider'](_0x4981b4[_0x4636d7(0x90)]),_0x4981b4['privateKey']&&(this['wallet']=new ethers['Wallet'](_0x4981b4['privateKey'],this['provider']));}static[_0x22ce63(0x8f)](_0x20969e){return ethers['hexlify'](ethers['toUtf8Bytes'](''+ANCHOR_PREFIX+_0x20969e));}static['decodeData'](_0x16f738){const _0x3edfb3=_0x22ce63,_0x56e8b9={};_0x56e8b9['oYlNc']=_0x3edfb3(0xa7);const _0x2cb1d2=_0x56e8b9;try{const _0x3eebec=ethers['toUtf8String'](_0x16f738);if(_0x3eebec[_0x3edfb3(0x9f)](ANCHOR_PREFIX))return _0x3eebec[_0x3edfb3(0xa4)](ANCHOR_PREFIX[_0x3edfb3(0x80)]);return null;}catch{return _0x2cb1d2['oYlNc']===_0x2cb1d2['oYlNc']?null:_0x2adadd['slice'](_0x1d4201['length']);}}async[_0x22ce63(0x89)](_0x2be330,_0x21bd6c){const _0x1a7b78=_0x22ce63,_0x351c4e={};_0x351c4e[_0x1a7b78(0xa0)]='kKvHo';const _0x542621=_0x351c4e;if(!this['wallet'])throw new Error(this['name']+':\x20Cannot\x20anchor\x20without\x20a\x20private\x20key');const _0x1d37ae=EvmAnchorProvider[_0x1a7b78(0x8f)](_0x2be330);try{const _0x48495f=await this['wallet']['sendTransaction']({'to':this[_0x1a7b78(0x9b)]['address'],'value':0x0n,'data':_0x1d37ae}),_0x42608a=await _0x48495f['wait']();if(!_0x42608a){if(_0x1a7b78(0x8c)!==_0x542621[_0x1a7b78(0xa0)])throw new Error(_0x1a7b78(0x88));else{const _0x26c0ce=_0x3ed2a5['toUtf8String'](_0x50b442);if(_0x26c0ce[_0x1a7b78(0x9f)](_0x174712))return _0x26c0ce['slice'](_0x3a8e71['length']);return null;}}return{'hash':_0x2be330,'txHash':_0x42608a[_0x1a7b78(0x7d)],'chain':this['chain'],'timestamp':Date['now'](),'blockNumber':_0x42608a[_0x1a7b78(0x83)],'metadata':_0x21bd6c};}catch(_0x43ca66){const _0xc34161=_0x43ca66 instanceof Error?_0x43ca66['message']:String(_0x43ca66);throw new Error(this[_0x1a7b78(0xa6)]+_0x1a7b78(0x8d)+_0xc34161);}}async[_0x22ce63(0x9e)](_0x43ea86,_0x7aab4c){const _0x22f3b3=_0x22ce63,_0x49a14b={};_0x49a14b[_0x22f3b3(0x93)]=_0x22f3b3(0x8b),_0x49a14b['NekCb']=function(_0xb62025,_0x453874){return _0xb62025===_0x453874;},_0x49a14b[_0x22f3b3(0x97)]='Transaction\x20data\x20does\x20not\x20contain\x20a\x20valid\x20anchor',_0x49a14b['qMTix']=function(_0x668f25,_0x4785ab){return _0x668f25*_0x4785ab;},_0x49a14b['jErgJ']='Hash\x20matches\x20on-chain\x20data';const _0x2b824d=_0x49a14b;try{const _0x2fa53d=await this[_0x22f3b3(0xa2)][_0x22f3b3(0x87)](_0x7aab4c);if(!_0x2fa53d){const _0x286088={};return _0x286088[_0x22f3b3(0xa8)]=![],_0x286088['hash']=_0x43ea86,_0x286088[_0x22f3b3(0x9d)]=_0x7aab4c,_0x286088[_0x22f3b3(0x86)]=this['chain'],_0x286088['detail']=_0x2b824d[_0x22f3b3(0x93)],_0x286088;}const _0x47f536=EvmAnchorProvider[_0x22f3b3(0x94)](_0x2fa53d['data']);if(_0x2b824d['NekCb'](_0x47f536,null)){const _0x1dc1f3={};return _0x1dc1f3[_0x22f3b3(0xa8)]=![],_0x1dc1f3['hash']=_0x43ea86,_0x1dc1f3['txHash']=_0x7aab4c,_0x1dc1f3['chain']=this[_0x22f3b3(0x86)],_0x1dc1f3[_0x22f3b3(0x7e)]=_0x2b824d[_0x22f3b3(0x97)],_0x1dc1f3;}const _0x49e04f=_0x47f536===_0x43ea86;let _0x14fbf8;if(_0x2fa53d['blockNumber'])try{const _0x4cf563=await this[_0x22f3b3(0xa2)]['getBlock'](_0x2fa53d['blockNumber']);_0x14fbf8=_0x4cf563?_0x2b824d['qMTix'](_0x4cf563[_0x22f3b3(0x81)],0x3e8):undefined;}catch{}const _0x522d07={};return _0x522d07['valid']=_0x49e04f,_0x522d07['hash']=_0x43ea86,_0x522d07[_0x22f3b3(0x9d)]=_0x7aab4c,_0x522d07['chain']=this['chain'],_0x522d07[_0x22f3b3(0x91)]=_0x14fbf8,_0x522d07['detail']=_0x49e04f?_0x2b824d['jErgJ']:'Hash\x20mismatch:\x20expected\x20\x22'+_0x43ea86+'\x22,\x20found\x20\x22'+_0x47f536+'\x22',_0x522d07;}catch(_0x39a9d3){const _0x194b47=_0x39a9d3 instanceof Error?_0x39a9d3[_0x22f3b3(0x9a)]:String(_0x39a9d3),_0x3338d4={};return _0x3338d4[_0x22f3b3(0xa8)]=![],_0x3338d4[_0x22f3b3(0x7d)]=_0x43ea86,_0x3338d4['txHash']=_0x7aab4c,_0x3338d4[_0x22f3b3(0x86)]=this['chain'],_0x3338d4[_0x22f3b3(0x7e)]='Verification\x20error:\x20'+_0x194b47,_0x3338d4;}}async['lookup'](_0x2fa321){return[];}async[_0x22ce63(0xa1)](){const _0x298059=_0x22ce63,_0x2724e7={};_0x2724e7[_0x298059(0xa3)]='dtcNk';const _0x2f3583=_0x2724e7;try{if(_0x2f3583[_0x298059(0xa3)]!=='MZYry')return await this[_0x298059(0xa2)][_0x298059(0xa5)](),!![];else this['wallet']=new _0x5cfee3['Wallet'](_0x2df7df[_0x298059(0x85)],this[_0x298059(0xa2)]);}catch{return![];}}}