@arbilink/sdk 0.1.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/dist/utils.js ADDED
@@ -0,0 +1,99 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.encodeCall = encodeCall;
4
+ exports.formatMessageId = formatMessageId;
5
+ exports.statusLabel = statusLabel;
6
+ exports.resolveChainId = resolveChainId;
7
+ exports.estimateDeliveryTime = estimateDeliveryTime;
8
+ exports.parseStatusCode = parseStatusCode;
9
+ exports.formatEth = formatEth;
10
+ const viem_1 = require("viem");
11
+ const constants_1 = require("./constants");
12
+ // ── Encoding helpers ──────────────────────────────────────────────────────────
13
+ /**
14
+ * Encode a contract function call into hex calldata ready for cross-chain delivery.
15
+ *
16
+ * @example
17
+ * ```typescript
18
+ * const data = encodeCall({
19
+ * abi: parseAbi(['function mint(address to, uint256 amount)']),
20
+ * functionName: 'mint',
21
+ * args: ['0x742d35Cc...', 1000n],
22
+ * });
23
+ * ```
24
+ */
25
+ function encodeCall(params) {
26
+ return (0, viem_1.encodeFunctionData)({
27
+ abi: params.abi,
28
+ functionName: params.functionName,
29
+ args: params.args ?? [],
30
+ });
31
+ }
32
+ // ── Formatting ────────────────────────────────────────────────────────────────
33
+ /**
34
+ * Format a numeric message ID as a zero-padded string.
35
+ * @example formatMessageId(42n) → "#000042"
36
+ */
37
+ function formatMessageId(id) {
38
+ return `#${id.toString().padStart(6, '0')}`;
39
+ }
40
+ /**
41
+ * Human-readable label for a message status.
42
+ */
43
+ function statusLabel(status) {
44
+ const labels = {
45
+ pending: 'Pending',
46
+ relayed: 'Relayed (in challenge window)',
47
+ confirmed: 'Confirmed',
48
+ failed: 'Failed',
49
+ };
50
+ return labels[status];
51
+ }
52
+ // ── Chain helpers ─────────────────────────────────────────────────────────────
53
+ /**
54
+ * Resolve a chain name or numeric ID to a numeric chain ID.
55
+ * Throws `ArbiLinkError` for unknown chains.
56
+ */
57
+ function resolveChainId(chain) {
58
+ if (typeof chain === 'number')
59
+ return chain;
60
+ const id = constants_1.CHAIN_IDS[chain.toLowerCase()];
61
+ if (id == null) {
62
+ throw new Error(`Unknown chain "${chain}". Supported names: ${Object.keys(constants_1.CHAIN_IDS).join(', ')}`);
63
+ }
64
+ return id;
65
+ }
66
+ /**
67
+ * Estimate message delivery time in seconds for a given destination chain.
68
+ *
69
+ * This is a rough heuristic based on block times – actual delivery depends on
70
+ * relayer availability and the 5-minute challenge window.
71
+ */
72
+ function estimateDeliveryTime(chainId) {
73
+ const CHALLENGE_WINDOW = 300; // 5 min in seconds
74
+ const FINALITY_TIMES = {
75
+ 11155111: 15, // Ethereum Sepolia
76
+ 84532: 2, // Base Sepolia
77
+ 80002: 2, // Polygon Amoy
78
+ 11155420: 2, // Optimism Sepolia
79
+ };
80
+ return CHALLENGE_WINDOW + (FINALITY_TIMES[chainId] ?? 12);
81
+ }
82
+ // ── Status helpers ────────────────────────────────────────────────────────────
83
+ const STATUS_MAP = ['pending', 'relayed', 'confirmed', 'failed'];
84
+ /**
85
+ * Convert the on-chain numeric status code to the SDK string representation.
86
+ */
87
+ function parseStatusCode(code) {
88
+ return STATUS_MAP[code] ?? 'pending';
89
+ }
90
+ // ── Wei helpers ───────────────────────────────────────────────────────────────
91
+ /**
92
+ * Format a wei value as a human-readable ETH string.
93
+ * @example formatEth(1_000_000_000_000_000n) → "0.001 ETH"
94
+ */
95
+ function formatEth(wei) {
96
+ const eth = Number(wei) / 1e18;
97
+ return `${eth.toFixed(6).replace(/\.?0+$/, '')} ETH`;
98
+ }
99
+ //# sourceMappingURL=utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":";;AAkBA,gCAUC;AAQD,0CAEC;AAKD,kCAQC;AAQD,wCAUC;AAQD,oDAWC;AASD,0CAEC;AAQD,8BAGC;AA9GD,+BAAoD;AAEpD,2CAAwC;AAExC,iFAAiF;AAEjF;;;;;;;;;;;GAWG;AACH,SAAgB,UAAU,CAAC,MAI1B;IACC,OAAO,IAAA,yBAAkB,EAAC;QACxB,GAAG,EAAW,MAAM,CAAC,GAAG;QACxB,YAAY,EAAE,MAAM,CAAC,YAAY;QACjC,IAAI,EAAU,MAAM,CAAC,IAAI,IAAI,EAAE;KAChC,CAAW,CAAC;AACf,CAAC;AAED,iFAAiF;AAEjF;;;GAGG;AACH,SAAgB,eAAe,CAAC,EAAU;IACxC,OAAO,IAAI,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC;AAC9C,CAAC;AAED;;GAEG;AACH,SAAgB,WAAW,CAAC,MAAqB;IAC/C,MAAM,MAAM,GAAkC;QAC5C,OAAO,EAAI,SAAS;QACpB,OAAO,EAAI,+BAA+B;QAC1C,SAAS,EAAE,WAAW;QACtB,MAAM,EAAK,QAAQ;KACpB,CAAC;IACF,OAAO,MAAM,CAAC,MAAM,CAAC,CAAC;AACxB,CAAC;AAED,iFAAiF;AAEjF;;;GAGG;AACH,SAAgB,cAAc,CAAC,KAAsB;IACnD,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC;IAE5C,MAAM,EAAE,GAAG,qBAAS,CAAC,KAAK,CAAC,WAAW,EAA4B,CAAC,CAAC;IACpE,IAAI,EAAE,IAAI,IAAI,EAAE,CAAC;QACf,MAAM,IAAI,KAAK,CACb,kBAAkB,KAAK,uBAAuB,MAAM,CAAC,IAAI,CAAC,qBAAS,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAClF,CAAC;IACJ,CAAC;IACD,OAAO,EAAE,CAAC;AACZ,CAAC;AAED;;;;;GAKG;AACH,SAAgB,oBAAoB,CAAC,OAAe;IAClD,MAAM,gBAAgB,GAAG,GAAG,CAAC,CAAC,mBAAmB;IAEjD,MAAM,cAAc,GAA2B;QAC7C,QAAQ,EAAE,EAAE,EAAG,mBAAmB;QAClC,KAAK,EAAK,CAAC,EAAI,eAAe;QAC9B,KAAK,EAAK,CAAC,EAAI,eAAe;QAC9B,QAAQ,EAAE,CAAC,EAAI,mBAAmB;KACnC,CAAC;IAEF,OAAO,gBAAgB,GAAG,CAAC,cAAc,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC;AAC5D,CAAC;AAED,iFAAiF;AAEjF,MAAM,UAAU,GAAoB,CAAC,SAAS,EAAE,SAAS,EAAE,WAAW,EAAE,QAAQ,CAAC,CAAC;AAElF;;GAEG;AACH,SAAgB,eAAe,CAAC,IAAY;IAC1C,OAAO,UAAU,CAAC,IAAI,CAAC,IAAI,SAAS,CAAC;AACvC,CAAC;AAED,iFAAiF;AAEjF;;;GAGG;AACH,SAAgB,SAAS,CAAC,GAAW;IACnC,MAAM,GAAG,GAAG,MAAM,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC;IAC/B,OAAO,GAAG,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,MAAM,CAAC;AACvD,CAAC"}
package/package.json ADDED
@@ -0,0 +1,46 @@
1
+ {
2
+ "name": "@arbilink/sdk",
3
+ "version": "0.1.0",
4
+ "description": "Cross-chain messaging SDK for Arbitrum — send messages to any chain with one function call",
5
+ "keywords": [
6
+ "arbitrum",
7
+ "cross-chain",
8
+ "messaging",
9
+ "bridge",
10
+ "stylus",
11
+ "web3"
12
+ ],
13
+ "license": "MIT",
14
+ "author": "ArbiLink",
15
+ "repository": {
16
+ "type": "git",
17
+ "url": "https://github.com/Martins-O/ArbiLink.git",
18
+ "directory": "packages/sdk"
19
+ },
20
+ "main": "dist/index.js",
21
+ "types": "dist/index.d.ts",
22
+ "files": [
23
+ "dist",
24
+ "src"
25
+ ],
26
+ "dependencies": {
27
+ "ethers": "^6.9.0",
28
+ "viem": "^2.0.0"
29
+ },
30
+ "devDependencies": {
31
+ "@types/node": "^20.0.0",
32
+ "typescript": "^5.3.0"
33
+ },
34
+ "peerDependencies": {
35
+ "ethers": "^6.9.0"
36
+ },
37
+ "engines": {
38
+ "node": ">=18.0.0"
39
+ },
40
+ "scripts": {
41
+ "build": "tsc --project tsconfig.json",
42
+ "build:watch": "tsc --project tsconfig.json --watch",
43
+ "clean": "rm -rf dist",
44
+ "type-check": "tsc --noEmit"
45
+ }
46
+ }
@@ -0,0 +1,301 @@
1
+ import { ethers } from 'ethers';
2
+ import MessageHubABI from './abi/MessageHub.json';
3
+ import { MESSAGE_HUB_ADDRESS } from './constants';
4
+ import { ArbiLinkError, type Message, type MessageStatus, type SendMessageParams, type WatchOptions } from './types';
5
+ import { parseStatusCode, resolveChainId } from './utils';
6
+
7
+ // ── ArbiLink SDK ──────────────────────────────────────────────────────────────
8
+
9
+ /**
10
+ * ArbiLink SDK — send cross-chain messages from Arbitrum to any supported chain.
11
+ *
12
+ * @example
13
+ * ```typescript
14
+ * // With a signer (full read/write access)
15
+ * const arbiLink = new ArbiLink(signer);
16
+ *
17
+ * // With a provider (read-only: getMessageStatus, calculateFee)
18
+ * const arbiLink = new ArbiLink(provider);
19
+ * ```
20
+ */
21
+ export class ArbiLink {
22
+ private readonly provider: ethers.Provider;
23
+ private readonly signer: ethers.Signer | null;
24
+ private readonly messageHub: ethers.Contract;
25
+ private readonly iface: ethers.Interface;
26
+
27
+ constructor(signerOrProvider: ethers.Signer | ethers.Provider) {
28
+ // Distinguish signer from provider: signers expose `getAddress()`
29
+ const isSigner = typeof (signerOrProvider as ethers.Signer).getAddress === 'function';
30
+
31
+ if (isSigner) {
32
+ this.signer = signerOrProvider as ethers.Signer;
33
+ const p = this.signer.provider;
34
+ if (!p) throw new ArbiLinkError('Signer has no attached provider. Connect your signer to a network first.');
35
+ this.provider = p;
36
+ } else {
37
+ this.signer = null;
38
+ this.provider = signerOrProvider as ethers.Provider;
39
+ }
40
+
41
+ this.iface = new ethers.Interface(MessageHubABI);
42
+
43
+ this.messageHub = new ethers.Contract(
44
+ MESSAGE_HUB_ADDRESS,
45
+ MessageHubABI,
46
+ isSigner ? this.signer! : this.provider,
47
+ );
48
+ }
49
+
50
+ // ── Core: send ─────────────────────────────────────────────────────────────
51
+
52
+ /**
53
+ * Send a cross-chain message from Arbitrum to any supported chain.
54
+ *
55
+ * @returns The message ID assigned by the hub.
56
+ *
57
+ * @example
58
+ * ```typescript
59
+ * const arbiLink = new ArbiLink(signer);
60
+ *
61
+ * const messageId = await arbiLink.sendMessage({
62
+ * to: 'ethereum',
63
+ * target: '0x742d35Cc6634C0532925a3b844BC454e4438f44e',
64
+ * data: encodeCall({
65
+ * abi: myABI,
66
+ * functionName: 'mint',
67
+ * args: [recipient, amount],
68
+ * }),
69
+ * });
70
+ *
71
+ * console.log('Sent:', formatMessageId(messageId)); // → "#000001"
72
+ * ```
73
+ */
74
+ async sendMessage(params: SendMessageParams): Promise<bigint> {
75
+ this.requireSigner();
76
+
77
+ const chainId = resolveChainId(params.to);
78
+ const fee = params.fee ?? await this.calculateFee(chainId);
79
+
80
+ let tx: ethers.TransactionResponse;
81
+ try {
82
+ tx = await this.messageHub.sendMessage(
83
+ chainId,
84
+ params.target,
85
+ params.data,
86
+ { value: fee },
87
+ ) as ethers.TransactionResponse;
88
+ } catch (err) {
89
+ throw ArbiLinkError.from(err, `Failed to send message to chain ${chainId}`);
90
+ }
91
+
92
+ const receipt = await tx.wait();
93
+ if (!receipt) throw new ArbiLinkError('Transaction receipt is null – the tx may have been dropped');
94
+
95
+ // Parse MessageSent event to extract the assigned message ID
96
+ for (const log of receipt.logs) {
97
+ try {
98
+ const parsed = this.iface.parseLog({ topics: [...log.topics], data: log.data });
99
+ if (parsed?.name === 'MessageSent') {
100
+ return parsed.args.messageId as bigint;
101
+ }
102
+ } catch {
103
+ // Log from a different contract – skip
104
+ }
105
+ }
106
+
107
+ throw new ArbiLinkError(
108
+ 'MessageSent event not found in receipt. The transaction may have succeeded but used an unexpected hub version.',
109
+ );
110
+ }
111
+
112
+ // ── Core: status ───────────────────────────────────────────────────────────
113
+
114
+ /**
115
+ * Query the current status and metadata of a message.
116
+ *
117
+ * Fetches the status code from the hub and enriches it with data from
118
+ * `MessageSent` and `MessageConfirmed` event logs.
119
+ *
120
+ * @example
121
+ * ```typescript
122
+ * const msg = await arbiLink.getMessageStatus(messageId);
123
+ * console.log(msg.status); // 'pending' | 'confirmed'
124
+ * console.log(msg.destinationChain); // 11155111
125
+ * ```
126
+ */
127
+ async getMessageStatus(messageId: bigint): Promise<Message> {
128
+ try {
129
+ const statusCode = await this.messageHub.getMessageStatus(messageId) as bigint;
130
+ const status: MessageStatus = parseStatusCode(Number(statusCode));
131
+
132
+ // Enrich from MessageSent event
133
+ const sentFilter = this.messageHub.filters['MessageSent'](messageId);
134
+ const sentLogs = await this.messageHub.queryFilter(sentFilter);
135
+
136
+ let sender: string | undefined;
137
+ let destinationChain: number | undefined;
138
+ let target: string | undefined;
139
+ let data: string | undefined;
140
+ let feePaid: bigint | undefined;
141
+
142
+ if (sentLogs.length > 0) {
143
+ const e = sentLogs[0] as ethers.EventLog;
144
+ sender = e.args.sender as string;
145
+ destinationChain = Number(e.args.destinationChain);
146
+ target = e.args.target as string;
147
+ data = e.args.data as string;
148
+ feePaid = e.args.fee as bigint;
149
+ }
150
+
151
+ // Enrich from MessageConfirmed event (present only when confirmed)
152
+ let relayer: string | undefined;
153
+ if (status === 'confirmed' || status === 'relayed') {
154
+ const confirmedFilter = this.messageHub.filters['MessageConfirmed'](messageId);
155
+ const confirmedLogs = await this.messageHub.queryFilter(confirmedFilter);
156
+ if (confirmedLogs.length > 0) {
157
+ relayer = (confirmedLogs[0] as ethers.EventLog).args.relayer as string;
158
+ }
159
+ }
160
+
161
+ return {
162
+ id: messageId,
163
+ status,
164
+ sender,
165
+ destinationChain,
166
+ target,
167
+ data,
168
+ feePaid,
169
+ relayer,
170
+ };
171
+ } catch (err) {
172
+ throw ArbiLinkError.from(err, `Failed to fetch status for message #${messageId}`);
173
+ }
174
+ }
175
+
176
+ // ── Core: fee ──────────────────────────────────────────────────────────────
177
+
178
+ /**
179
+ * Fetch the base fee (in wei) required to send a message to `chainId`.
180
+ *
181
+ * @example
182
+ * ```typescript
183
+ * const fee = await arbiLink.calculateFee(11155111);
184
+ * console.log(formatEth(fee)); // "0.001 ETH"
185
+ * ```
186
+ */
187
+ async calculateFee(chainId: number): Promise<bigint> {
188
+ try {
189
+ return await this.messageHub.calculateFee(chainId) as bigint;
190
+ } catch (err) {
191
+ throw ArbiLinkError.from(err, `Failed to fetch fee for chain ${chainId}`);
192
+ }
193
+ }
194
+
195
+ // ── Core: watch ────────────────────────────────────────────────────────────
196
+
197
+ /**
198
+ * Subscribe to confirmation events for a given message.
199
+ *
200
+ * The callback fires when a `MessageConfirmed` event is emitted for this
201
+ * message ID. Call the returned function to unsubscribe.
202
+ *
203
+ * @example
204
+ * ```typescript
205
+ * const unwatch = arbiLink.watchMessage(messageId, (msg) => {
206
+ * console.log('Update:', msg.status);
207
+ * if (msg.status === 'confirmed') unwatch();
208
+ * });
209
+ * ```
210
+ */
211
+ watchMessage(
212
+ messageId: bigint,
213
+ callback: (message: Message) => void,
214
+ _options: WatchOptions = {},
215
+ ): () => void {
216
+ const confirmedFilter = this.messageHub.filters['MessageConfirmed'](messageId);
217
+
218
+ const listener = async (): Promise<void> => {
219
+ try {
220
+ const msg = await this.getMessageStatus(messageId);
221
+ callback(msg);
222
+ } catch (err) {
223
+ // Surface the error through the callback rather than throwing from
224
+ // an event listener (which would be silently swallowed by ethers)
225
+ console.error('[ArbiLink] watchMessage error:', err);
226
+ }
227
+ };
228
+
229
+ this.messageHub.on(confirmedFilter, listener);
230
+
231
+ return () => {
232
+ this.messageHub.off(confirmedFilter, listener);
233
+ };
234
+ }
235
+
236
+ // ── Relayer helpers ────────────────────────────────────────────────────────
237
+
238
+ /**
239
+ * Check whether `address` is a registered, active relayer.
240
+ */
241
+ async isActiveRelayer(address: string): Promise<boolean> {
242
+ return await this.messageHub.isActiveRelayer(address) as boolean;
243
+ }
244
+
245
+ /**
246
+ * Register the signer as a relayer by staking the required ETH.
247
+ * Fetches the minimum stake from the hub automatically.
248
+ *
249
+ * @param stakeOverride - Override the minimum stake amount (wei).
250
+ */
251
+ async registerRelayer(stakeOverride?: bigint): Promise<void> {
252
+ this.requireSigner();
253
+
254
+ const stake = stakeOverride ?? await this.messageHub.minStake() as bigint;
255
+
256
+ const tx = await this.messageHub.registerRelayer({ value: stake }) as ethers.TransactionResponse;
257
+ await tx.wait();
258
+ }
259
+
260
+ /**
261
+ * Withdraw the signer's relayer stake and deregister.
262
+ */
263
+ async exitRelayer(): Promise<void> {
264
+ this.requireSigner();
265
+ const tx = await this.messageHub.exitRelayer() as ethers.TransactionResponse;
266
+ await tx.wait();
267
+ }
268
+
269
+ // ── Hub info ───────────────────────────────────────────────────────────────
270
+
271
+ /**
272
+ * Total number of messages sent through the hub.
273
+ */
274
+ async messageCount(): Promise<bigint> {
275
+ return await this.messageHub.messageCount() as bigint;
276
+ }
277
+
278
+ /**
279
+ * The hub owner address.
280
+ */
281
+ async owner(): Promise<string> {
282
+ return await this.messageHub.owner() as string;
283
+ }
284
+
285
+ /**
286
+ * Minimum stake (wei) required to register as a relayer.
287
+ */
288
+ async minStake(): Promise<bigint> {
289
+ return await this.messageHub.minStake() as bigint;
290
+ }
291
+
292
+ // ── Private helpers ────────────────────────────────────────────────────────
293
+
294
+ private requireSigner(): void {
295
+ if (!this.signer) {
296
+ throw new ArbiLinkError(
297
+ 'This operation requires a Signer. Initialize ArbiLink with an ethers.Signer instead of a Provider.',
298
+ );
299
+ }
300
+ }
301
+ }
@@ -0,0 +1,156 @@
1
+ [
2
+ {
3
+ "type": "function",
4
+ "name": "initialize",
5
+ "inputs": [
6
+ { "name": "min_stake", "type": "uint256" },
7
+ { "name": "challenge_period", "type": "uint256" }
8
+ ],
9
+ "outputs": [],
10
+ "stateMutability": "nonpayable"
11
+ },
12
+ {
13
+ "type": "function",
14
+ "name": "sendMessage",
15
+ "inputs": [
16
+ { "name": "destination_chain", "type": "uint32" },
17
+ { "name": "target", "type": "address" },
18
+ { "name": "data", "type": "bytes" }
19
+ ],
20
+ "outputs": [{ "name": "", "type": "uint256" }],
21
+ "stateMutability": "payable"
22
+ },
23
+ {
24
+ "type": "function",
25
+ "name": "confirmDelivery",
26
+ "inputs": [
27
+ { "name": "message_id", "type": "uint256" },
28
+ { "name": "_proof", "type": "bytes" }
29
+ ],
30
+ "outputs": [],
31
+ "stateMutability": "nonpayable"
32
+ },
33
+ {
34
+ "type": "function",
35
+ "name": "registerRelayer",
36
+ "inputs": [],
37
+ "outputs": [],
38
+ "stateMutability": "payable"
39
+ },
40
+ {
41
+ "type": "function",
42
+ "name": "exitRelayer",
43
+ "inputs": [],
44
+ "outputs": [],
45
+ "stateMutability": "nonpayable"
46
+ },
47
+ {
48
+ "type": "function",
49
+ "name": "addChain",
50
+ "inputs": [
51
+ { "name": "chain_id", "type": "uint32" },
52
+ { "name": "receiver_address", "type": "address" },
53
+ { "name": "base_fee", "type": "uint256" }
54
+ ],
55
+ "outputs": [],
56
+ "stateMutability": "nonpayable"
57
+ },
58
+ {
59
+ "type": "function",
60
+ "name": "getMessageStatus",
61
+ "inputs": [{ "name": "message_id", "type": "uint256" }],
62
+ "outputs": [{ "name": "", "type": "uint8" }],
63
+ "stateMutability": "view"
64
+ },
65
+ {
66
+ "type": "function",
67
+ "name": "calculateFee",
68
+ "inputs": [{ "name": "destination_chain", "type": "uint32" }],
69
+ "outputs": [{ "name": "", "type": "uint256" }],
70
+ "stateMutability": "view"
71
+ },
72
+ {
73
+ "type": "function",
74
+ "name": "isActiveRelayer",
75
+ "inputs": [{ "name": "relayer", "type": "address" }],
76
+ "outputs": [{ "name": "", "type": "bool" }],
77
+ "stateMutability": "view"
78
+ },
79
+ {
80
+ "type": "function",
81
+ "name": "messageCount",
82
+ "inputs": [],
83
+ "outputs": [{ "name": "", "type": "uint256" }],
84
+ "stateMutability": "view"
85
+ },
86
+ {
87
+ "type": "function",
88
+ "name": "owner",
89
+ "inputs": [],
90
+ "outputs": [{ "name": "", "type": "address" }],
91
+ "stateMutability": "view"
92
+ },
93
+ {
94
+ "type": "function",
95
+ "name": "minStake",
96
+ "inputs": [],
97
+ "outputs": [{ "name": "", "type": "uint256" }],
98
+ "stateMutability": "view"
99
+ },
100
+ {
101
+ "type": "event",
102
+ "name": "MessageSent",
103
+ "inputs": [
104
+ { "name": "messageId", "type": "uint256", "indexed": true },
105
+ { "name": "sender", "type": "address", "indexed": true },
106
+ { "name": "destinationChain", "type": "uint32", "indexed": false },
107
+ { "name": "target", "type": "address", "indexed": false },
108
+ { "name": "data", "type": "bytes", "indexed": false },
109
+ { "name": "fee", "type": "uint256", "indexed": false }
110
+ ]
111
+ },
112
+ {
113
+ "type": "event",
114
+ "name": "MessageConfirmed",
115
+ "inputs": [
116
+ { "name": "messageId", "type": "uint256", "indexed": true },
117
+ { "name": "relayer", "type": "address", "indexed": true },
118
+ { "name": "timestamp", "type": "uint256", "indexed": false }
119
+ ]
120
+ },
121
+ {
122
+ "type": "event",
123
+ "name": "RelayerRegistered",
124
+ "inputs": [
125
+ { "name": "relayer", "type": "address", "indexed": true },
126
+ { "name": "stake", "type": "uint256", "indexed": false }
127
+ ]
128
+ },
129
+ {
130
+ "type": "event",
131
+ "name": "RelayerExited",
132
+ "inputs": [
133
+ { "name": "relayer", "type": "address", "indexed": true },
134
+ { "name": "returned", "type": "uint256", "indexed": false }
135
+ ]
136
+ },
137
+ {
138
+ "type": "event",
139
+ "name": "ChainAdded",
140
+ "inputs": [
141
+ { "name": "chainId", "type": "uint32", "indexed": true },
142
+ { "name": "receiver", "type": "address", "indexed": false },
143
+ { "name": "baseFee", "type": "uint256", "indexed": false }
144
+ ]
145
+ },
146
+ { "type": "error", "name": "ChainNotSupported", "inputs": [{ "name": "chainId", "type": "uint32" }] },
147
+ { "type": "error", "name": "InsufficientFee", "inputs": [{ "name": "required", "type": "uint256" }, { "name": "provided", "type": "uint256" }] },
148
+ { "type": "error", "name": "MessageNotFound", "inputs": [{ "name": "messageId", "type": "uint256" }] },
149
+ { "type": "error", "name": "InsufficientStake", "inputs": [{ "name": "required", "type": "uint256" }, { "name": "provided", "type": "uint256" }] },
150
+ { "type": "error", "name": "Unauthorized", "inputs": [{ "name": "caller", "type": "address" }] },
151
+ { "type": "error", "name": "RelayerNotActive", "inputs": [{ "name": "relayer", "type": "address" }] },
152
+ { "type": "error", "name": "AlreadyRelayed", "inputs": [{ "name": "messageId", "type": "uint256" }] },
153
+ { "type": "error", "name": "TransferFailed", "inputs": [] },
154
+ { "type": "error", "name": "ZeroAddress", "inputs": [] },
155
+ { "type": "error", "name": "AlreadyInitialized", "inputs": [] }
156
+ ]