@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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Martins-O
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,255 @@
1
+ # @arbilink/sdk
2
+
3
+ Cross-chain messaging made simple. Send messages from **Arbitrum** to any supported chain with a single function call.
4
+
5
+ Built on top of the ArbiLink MessageHub — an optimistic cross-chain relay protocol running on Arbitrum Stylus.
6
+
7
+ ## Installation
8
+
9
+ ```bash
10
+ npm install @arbilink/sdk ethers
11
+ # or
12
+ yarn add @arbilink/sdk ethers
13
+ ```
14
+
15
+ ## Quick Start
16
+
17
+ ```typescript
18
+ import { ArbiLink, encodeCall } from '@arbilink/sdk';
19
+ import { ethers } from 'ethers';
20
+ import { parseAbi } from 'viem';
21
+
22
+ // 1. Connect a signer (must be on Arbitrum Sepolia)
23
+ const provider = new ethers.BrowserProvider(window.ethereum);
24
+ const signer = await provider.getSigner();
25
+
26
+ // 2. Initialise
27
+ const arbiLink = new ArbiLink(signer);
28
+
29
+ // 3. Send a cross-chain message
30
+ const messageId = await arbiLink.sendMessage({
31
+ to: 'ethereum', // destination chain name or numeric ID
32
+ target: '0x742d35Cc...', // contract to call on the destination chain
33
+ data: encodeCall({
34
+ abi: parseAbi(['function mint(address to, uint256 amount)']),
35
+ functionName: 'mint',
36
+ args: ['0xRecipient...', 1_000n],
37
+ }),
38
+ });
39
+
40
+ console.log('Message sent! ID:', messageId);
41
+
42
+ // 4. Watch for delivery
43
+ const unwatch = arbiLink.watchMessage(messageId, (msg) => {
44
+ console.log('Status update:', msg.status);
45
+ if (msg.status === 'confirmed') {
46
+ console.log('Message delivered!');
47
+ unwatch();
48
+ }
49
+ });
50
+ ```
51
+
52
+ ## API Reference
53
+
54
+ ### `new ArbiLink(signerOrProvider)`
55
+
56
+ | Mode | Arg | Read | Write |
57
+ |------|-----|------|-------|
58
+ | Full | `ethers.Signer` | ✅ | ✅ |
59
+ | Read-only | `ethers.Provider` | ✅ | ❌ |
60
+
61
+ ---
62
+
63
+ ### `sendMessage(params)` → `Promise<bigint>`
64
+
65
+ Send a cross-chain message. Returns the message ID.
66
+
67
+ ```typescript
68
+ const messageId = await arbiLink.sendMessage({
69
+ to: 'base', // 'ethereum' | 'base' | 'polygon' | 'optimism' | chainId
70
+ target: '0xTarget...',
71
+ data: '0xcalldata...',
72
+ fee: 1_000_000_000_000_000n, // optional – fetched from hub if omitted
73
+ });
74
+ ```
75
+
76
+ ---
77
+
78
+ ### `getMessageStatus(messageId)` → `Promise<Message>`
79
+
80
+ ```typescript
81
+ const msg = await arbiLink.getMessageStatus(1n);
82
+
83
+ console.log(msg.status); // 'pending' | 'relayed' | 'confirmed' | 'failed'
84
+ console.log(msg.sender); // address that sent the message
85
+ console.log(msg.destinationChain); // numeric chain ID
86
+ console.log(msg.feePaid); // bigint (wei)
87
+ console.log(msg.relayer); // relayer address (once confirmed)
88
+ ```
89
+
90
+ ---
91
+
92
+ ### `calculateFee(chainId)` → `Promise<bigint>`
93
+
94
+ ```typescript
95
+ const fee = await arbiLink.calculateFee(11155111);
96
+ console.log(formatEth(fee)); // "0.001 ETH"
97
+ ```
98
+
99
+ ---
100
+
101
+ ### `watchMessage(messageId, callback)` → `() => void`
102
+
103
+ Subscribe to `MessageConfirmed` and `MessageChallenged` events.
104
+ Returns an **unsubscribe** function.
105
+
106
+ ```typescript
107
+ const unwatch = arbiLink.watchMessage(messageId, (msg) => {
108
+ if (msg.status === 'confirmed' || msg.status === 'failed') {
109
+ unwatch();
110
+ }
111
+ });
112
+ ```
113
+
114
+ ---
115
+
116
+ ### `getChainInfo(chainId)` → `Promise<{ enabled, receiverAddress, baseFee } | null>`
117
+
118
+ ```typescript
119
+ const info = await arbiLink.getChainInfo(11155111);
120
+ console.log(info?.enabled); // true
121
+ console.log(info?.receiverAddress); // '0x...'
122
+ console.log(info?.baseFee); // bigint
123
+ ```
124
+
125
+ ---
126
+
127
+ ### `registerRelayer(stakeOverride?)` / `exitRelayer()`
128
+
129
+ ```typescript
130
+ // Register with the hub's minimum stake
131
+ await arbiLink.registerRelayer();
132
+
133
+ // Or override the stake amount
134
+ await arbiLink.registerRelayer(2_000_000_000_000_000_000n); // 2 ETH
135
+
136
+ // Withdraw stake and deregister
137
+ await arbiLink.exitRelayer();
138
+ ```
139
+
140
+ ---
141
+
142
+ ## Utility Functions
143
+
144
+ ```typescript
145
+ import {
146
+ encodeCall,
147
+ formatMessageId,
148
+ formatEth,
149
+ statusLabel,
150
+ estimateDeliveryTime,
151
+ } from '@arbilink/sdk';
152
+
153
+ encodeCall({ abi, functionName, args }); // → '0x...'
154
+ formatMessageId(42n); // → '#000042'
155
+ formatEth(1_000_000_000_000_000n); // → '0.001 ETH'
156
+ statusLabel('confirmed'); // → 'Confirmed'
157
+ estimateDeliveryTime(11155111); // → seconds (int)
158
+ ```
159
+
160
+ ---
161
+
162
+ ## Supported Chains
163
+
164
+ | Chain | Name | Chain ID | Status |
165
+ |-------|------|----------|--------|
166
+ | Ethereum Sepolia | `'ethereum'` | 11155111 | ✅ Supported |
167
+ | Base Sepolia | `'base'` | 84532 | ✅ Supported |
168
+ | Polygon Amoy | `'polygon'` | 80002 | 🔜 Coming soon |
169
+ | Optimism Sepolia | `'optimism'` | 11155420 | 🔜 Coming soon |
170
+
171
+ ---
172
+
173
+ ## Full Examples
174
+
175
+ ### NFT Mint on Ethereum
176
+
177
+ ```typescript
178
+ import { ArbiLink, encodeCall } from '@arbilink/sdk';
179
+ import { parseAbi } from 'viem';
180
+
181
+ const arbiLink = new ArbiLink(signer);
182
+
183
+ const data = encodeCall({
184
+ abi: parseAbi(['function mint(address to, uint256 tokenId)']),
185
+ functionName: 'mint',
186
+ args: ['0xRecipient...', 1n],
187
+ });
188
+
189
+ const messageId = await arbiLink.sendMessage({
190
+ to: 'ethereum',
191
+ target: NFT_CONTRACT_ADDRESS,
192
+ data,
193
+ });
194
+ ```
195
+
196
+ ### Token Transfer on Base
197
+
198
+ ```typescript
199
+ const data = encodeCall({
200
+ abi: parseAbi(['function transfer(address to, uint256 amount)']),
201
+ functionName: 'transfer',
202
+ args: [recipient, amount],
203
+ });
204
+
205
+ const messageId = await arbiLink.sendMessage({
206
+ to: 'base',
207
+ target: TOKEN_CONTRACT_ADDRESS,
208
+ data,
209
+ });
210
+ ```
211
+
212
+ ### Read-only status polling (no wallet required)
213
+
214
+ ```typescript
215
+ import { ArbiLink } from '@arbilink/sdk';
216
+ import { ethers } from 'ethers';
217
+
218
+ const provider = new ethers.JsonRpcProvider('https://sepolia-rollup.arbitrum.io/rpc');
219
+ const arbiLink = new ArbiLink(provider);
220
+
221
+ const msg = await arbiLink.getMessageStatus(42n);
222
+ console.log(msg.status); // 'confirmed'
223
+ ```
224
+
225
+ ---
226
+
227
+ ## How ArbiLink Works
228
+
229
+ 1. **User** calls `sendMessage()` on the **MessageHub** (Arbitrum Stylus).
230
+ 2. **Relayers** watch for `MessageSent` events and deliver the message on the destination chain via `ArbiLinkReceiver.receiveMessage()`.
231
+ 3. The relayer submits an **ECDSA execution proof** and calls `confirm_delivery()` on the hub, opening a **5-minute challenge window**.
232
+ 4. Anyone can call `challenge_message()` with a fraud proof during that window. A valid fraud proof **slashes the relayer's stake**.
233
+ 5. After the window closes without a challenge, `finalize_message()` marks the message as **confirmed**.
234
+
235
+ ---
236
+
237
+ ## Configuration
238
+
239
+ After running `scripts/deploy.sh`, update `src/constants.ts` with your deployed addresses:
240
+
241
+ ```typescript
242
+ // packages/sdk/src/constants.ts
243
+ export const MESSAGE_HUB_ADDRESS = '0xYourMessageHubAddress';
244
+
245
+ export const RECEIVER_ADDRESSES: Record<number, string> = {
246
+ 11155111: '0xYourEthReceiver',
247
+ 84532: '0xYourBaseReceiver',
248
+ };
249
+ ```
250
+
251
+ ---
252
+
253
+ ## License
254
+
255
+ MIT
@@ -0,0 +1,112 @@
1
+ import { ethers } from 'ethers';
2
+ import { type Message, type SendMessageParams, type WatchOptions } from './types';
3
+ /**
4
+ * ArbiLink SDK — send cross-chain messages from Arbitrum to any supported chain.
5
+ *
6
+ * @example
7
+ * ```typescript
8
+ * // With a signer (full read/write access)
9
+ * const arbiLink = new ArbiLink(signer);
10
+ *
11
+ * // With a provider (read-only: getMessageStatus, calculateFee)
12
+ * const arbiLink = new ArbiLink(provider);
13
+ * ```
14
+ */
15
+ export declare class ArbiLink {
16
+ private readonly provider;
17
+ private readonly signer;
18
+ private readonly messageHub;
19
+ private readonly iface;
20
+ constructor(signerOrProvider: ethers.Signer | ethers.Provider);
21
+ /**
22
+ * Send a cross-chain message from Arbitrum to any supported chain.
23
+ *
24
+ * @returns The message ID assigned by the hub.
25
+ *
26
+ * @example
27
+ * ```typescript
28
+ * const arbiLink = new ArbiLink(signer);
29
+ *
30
+ * const messageId = await arbiLink.sendMessage({
31
+ * to: 'ethereum',
32
+ * target: '0x742d35Cc6634C0532925a3b844BC454e4438f44e',
33
+ * data: encodeCall({
34
+ * abi: myABI,
35
+ * functionName: 'mint',
36
+ * args: [recipient, amount],
37
+ * }),
38
+ * });
39
+ *
40
+ * console.log('Sent:', formatMessageId(messageId)); // → "#000001"
41
+ * ```
42
+ */
43
+ sendMessage(params: SendMessageParams): Promise<bigint>;
44
+ /**
45
+ * Query the current status and metadata of a message.
46
+ *
47
+ * Fetches the status code from the hub and enriches it with data from
48
+ * `MessageSent` and `MessageConfirmed` event logs.
49
+ *
50
+ * @example
51
+ * ```typescript
52
+ * const msg = await arbiLink.getMessageStatus(messageId);
53
+ * console.log(msg.status); // 'pending' | 'confirmed'
54
+ * console.log(msg.destinationChain); // 11155111
55
+ * ```
56
+ */
57
+ getMessageStatus(messageId: bigint): Promise<Message>;
58
+ /**
59
+ * Fetch the base fee (in wei) required to send a message to `chainId`.
60
+ *
61
+ * @example
62
+ * ```typescript
63
+ * const fee = await arbiLink.calculateFee(11155111);
64
+ * console.log(formatEth(fee)); // "0.001 ETH"
65
+ * ```
66
+ */
67
+ calculateFee(chainId: number): Promise<bigint>;
68
+ /**
69
+ * Subscribe to confirmation events for a given message.
70
+ *
71
+ * The callback fires when a `MessageConfirmed` event is emitted for this
72
+ * message ID. Call the returned function to unsubscribe.
73
+ *
74
+ * @example
75
+ * ```typescript
76
+ * const unwatch = arbiLink.watchMessage(messageId, (msg) => {
77
+ * console.log('Update:', msg.status);
78
+ * if (msg.status === 'confirmed') unwatch();
79
+ * });
80
+ * ```
81
+ */
82
+ watchMessage(messageId: bigint, callback: (message: Message) => void, _options?: WatchOptions): () => void;
83
+ /**
84
+ * Check whether `address` is a registered, active relayer.
85
+ */
86
+ isActiveRelayer(address: string): Promise<boolean>;
87
+ /**
88
+ * Register the signer as a relayer by staking the required ETH.
89
+ * Fetches the minimum stake from the hub automatically.
90
+ *
91
+ * @param stakeOverride - Override the minimum stake amount (wei).
92
+ */
93
+ registerRelayer(stakeOverride?: bigint): Promise<void>;
94
+ /**
95
+ * Withdraw the signer's relayer stake and deregister.
96
+ */
97
+ exitRelayer(): Promise<void>;
98
+ /**
99
+ * Total number of messages sent through the hub.
100
+ */
101
+ messageCount(): Promise<bigint>;
102
+ /**
103
+ * The hub owner address.
104
+ */
105
+ owner(): Promise<string>;
106
+ /**
107
+ * Minimum stake (wei) required to register as a relayer.
108
+ */
109
+ minStake(): Promise<bigint>;
110
+ private requireSigner;
111
+ }
112
+ //# sourceMappingURL=ArbiLink.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ArbiLink.d.ts","sourceRoot":"","sources":["../src/ArbiLink.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAGhC,OAAO,EAAiB,KAAK,OAAO,EAAsB,KAAK,iBAAiB,EAAE,KAAK,YAAY,EAAE,MAAM,SAAS,CAAC;AAKrH;;;;;;;;;;;GAWG;AACH,qBAAa,QAAQ;IACnB,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAkB;IAC3C,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAuB;IAC9C,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAkB;IAC7C,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAmB;gBAE7B,gBAAgB,EAAE,MAAM,CAAC,MAAM,GAAG,MAAM,CAAC,QAAQ;IAyB7D;;;;;;;;;;;;;;;;;;;;;OAqBG;IACG,WAAW,CAAC,MAAM,EAAE,iBAAiB,GAAG,OAAO,CAAC,MAAM,CAAC;IAwC7D;;;;;;;;;;;;OAYG;IACG,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAmD3D;;;;;;;;OAQG;IACG,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAUpD;;;;;;;;;;;;;OAaG;IACH,YAAY,CACV,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,EACpC,QAAQ,GAAE,YAAiB,GAC1B,MAAM,IAAI;IAuBb;;OAEG;IACG,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAIxD;;;;;OAKG;IACG,eAAe,CAAC,aAAa,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAS5D;;OAEG;IACG,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC;IAQlC;;OAEG;IACG,YAAY,IAAI,OAAO,CAAC,MAAM,CAAC;IAIrC;;OAEG;IACG,KAAK,IAAI,OAAO,CAAC,MAAM,CAAC;IAI9B;;OAEG;IACG,QAAQ,IAAI,OAAO,CAAC,MAAM,CAAC;IAMjC,OAAO,CAAC,aAAa;CAOtB"}
@@ -0,0 +1,257 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.ArbiLink = void 0;
7
+ const ethers_1 = require("ethers");
8
+ const MessageHub_json_1 = __importDefault(require("./abi/MessageHub.json"));
9
+ const constants_1 = require("./constants");
10
+ const types_1 = require("./types");
11
+ const utils_1 = require("./utils");
12
+ // ── ArbiLink SDK ──────────────────────────────────────────────────────────────
13
+ /**
14
+ * ArbiLink SDK — send cross-chain messages from Arbitrum to any supported chain.
15
+ *
16
+ * @example
17
+ * ```typescript
18
+ * // With a signer (full read/write access)
19
+ * const arbiLink = new ArbiLink(signer);
20
+ *
21
+ * // With a provider (read-only: getMessageStatus, calculateFee)
22
+ * const arbiLink = new ArbiLink(provider);
23
+ * ```
24
+ */
25
+ class ArbiLink {
26
+ constructor(signerOrProvider) {
27
+ // Distinguish signer from provider: signers expose `getAddress()`
28
+ const isSigner = typeof signerOrProvider.getAddress === 'function';
29
+ if (isSigner) {
30
+ this.signer = signerOrProvider;
31
+ const p = this.signer.provider;
32
+ if (!p)
33
+ throw new types_1.ArbiLinkError('Signer has no attached provider. Connect your signer to a network first.');
34
+ this.provider = p;
35
+ }
36
+ else {
37
+ this.signer = null;
38
+ this.provider = signerOrProvider;
39
+ }
40
+ this.iface = new ethers_1.ethers.Interface(MessageHub_json_1.default);
41
+ this.messageHub = new ethers_1.ethers.Contract(constants_1.MESSAGE_HUB_ADDRESS, MessageHub_json_1.default, isSigner ? this.signer : this.provider);
42
+ }
43
+ // ── Core: send ─────────────────────────────────────────────────────────────
44
+ /**
45
+ * Send a cross-chain message from Arbitrum to any supported chain.
46
+ *
47
+ * @returns The message ID assigned by the hub.
48
+ *
49
+ * @example
50
+ * ```typescript
51
+ * const arbiLink = new ArbiLink(signer);
52
+ *
53
+ * const messageId = await arbiLink.sendMessage({
54
+ * to: 'ethereum',
55
+ * target: '0x742d35Cc6634C0532925a3b844BC454e4438f44e',
56
+ * data: encodeCall({
57
+ * abi: myABI,
58
+ * functionName: 'mint',
59
+ * args: [recipient, amount],
60
+ * }),
61
+ * });
62
+ *
63
+ * console.log('Sent:', formatMessageId(messageId)); // → "#000001"
64
+ * ```
65
+ */
66
+ async sendMessage(params) {
67
+ this.requireSigner();
68
+ const chainId = (0, utils_1.resolveChainId)(params.to);
69
+ const fee = params.fee ?? await this.calculateFee(chainId);
70
+ let tx;
71
+ try {
72
+ tx = await this.messageHub.sendMessage(chainId, params.target, params.data, { value: fee });
73
+ }
74
+ catch (err) {
75
+ throw types_1.ArbiLinkError.from(err, `Failed to send message to chain ${chainId}`);
76
+ }
77
+ const receipt = await tx.wait();
78
+ if (!receipt)
79
+ throw new types_1.ArbiLinkError('Transaction receipt is null – the tx may have been dropped');
80
+ // Parse MessageSent event to extract the assigned message ID
81
+ for (const log of receipt.logs) {
82
+ try {
83
+ const parsed = this.iface.parseLog({ topics: [...log.topics], data: log.data });
84
+ if (parsed?.name === 'MessageSent') {
85
+ return parsed.args.messageId;
86
+ }
87
+ }
88
+ catch {
89
+ // Log from a different contract – skip
90
+ }
91
+ }
92
+ throw new types_1.ArbiLinkError('MessageSent event not found in receipt. The transaction may have succeeded but used an unexpected hub version.');
93
+ }
94
+ // ── Core: status ───────────────────────────────────────────────────────────
95
+ /**
96
+ * Query the current status and metadata of a message.
97
+ *
98
+ * Fetches the status code from the hub and enriches it with data from
99
+ * `MessageSent` and `MessageConfirmed` event logs.
100
+ *
101
+ * @example
102
+ * ```typescript
103
+ * const msg = await arbiLink.getMessageStatus(messageId);
104
+ * console.log(msg.status); // 'pending' | 'confirmed'
105
+ * console.log(msg.destinationChain); // 11155111
106
+ * ```
107
+ */
108
+ async getMessageStatus(messageId) {
109
+ try {
110
+ const statusCode = await this.messageHub.getMessageStatus(messageId);
111
+ const status = (0, utils_1.parseStatusCode)(Number(statusCode));
112
+ // Enrich from MessageSent event
113
+ const sentFilter = this.messageHub.filters['MessageSent'](messageId);
114
+ const sentLogs = await this.messageHub.queryFilter(sentFilter);
115
+ let sender;
116
+ let destinationChain;
117
+ let target;
118
+ let data;
119
+ let feePaid;
120
+ if (sentLogs.length > 0) {
121
+ const e = sentLogs[0];
122
+ sender = e.args.sender;
123
+ destinationChain = Number(e.args.destinationChain);
124
+ target = e.args.target;
125
+ data = e.args.data;
126
+ feePaid = e.args.fee;
127
+ }
128
+ // Enrich from MessageConfirmed event (present only when confirmed)
129
+ let relayer;
130
+ if (status === 'confirmed' || status === 'relayed') {
131
+ const confirmedFilter = this.messageHub.filters['MessageConfirmed'](messageId);
132
+ const confirmedLogs = await this.messageHub.queryFilter(confirmedFilter);
133
+ if (confirmedLogs.length > 0) {
134
+ relayer = confirmedLogs[0].args.relayer;
135
+ }
136
+ }
137
+ return {
138
+ id: messageId,
139
+ status,
140
+ sender,
141
+ destinationChain,
142
+ target,
143
+ data,
144
+ feePaid,
145
+ relayer,
146
+ };
147
+ }
148
+ catch (err) {
149
+ throw types_1.ArbiLinkError.from(err, `Failed to fetch status for message #${messageId}`);
150
+ }
151
+ }
152
+ // ── Core: fee ──────────────────────────────────────────────────────────────
153
+ /**
154
+ * Fetch the base fee (in wei) required to send a message to `chainId`.
155
+ *
156
+ * @example
157
+ * ```typescript
158
+ * const fee = await arbiLink.calculateFee(11155111);
159
+ * console.log(formatEth(fee)); // "0.001 ETH"
160
+ * ```
161
+ */
162
+ async calculateFee(chainId) {
163
+ try {
164
+ return await this.messageHub.calculateFee(chainId);
165
+ }
166
+ catch (err) {
167
+ throw types_1.ArbiLinkError.from(err, `Failed to fetch fee for chain ${chainId}`);
168
+ }
169
+ }
170
+ // ── Core: watch ────────────────────────────────────────────────────────────
171
+ /**
172
+ * Subscribe to confirmation events for a given message.
173
+ *
174
+ * The callback fires when a `MessageConfirmed` event is emitted for this
175
+ * message ID. Call the returned function to unsubscribe.
176
+ *
177
+ * @example
178
+ * ```typescript
179
+ * const unwatch = arbiLink.watchMessage(messageId, (msg) => {
180
+ * console.log('Update:', msg.status);
181
+ * if (msg.status === 'confirmed') unwatch();
182
+ * });
183
+ * ```
184
+ */
185
+ watchMessage(messageId, callback, _options = {}) {
186
+ const confirmedFilter = this.messageHub.filters['MessageConfirmed'](messageId);
187
+ const listener = async () => {
188
+ try {
189
+ const msg = await this.getMessageStatus(messageId);
190
+ callback(msg);
191
+ }
192
+ catch (err) {
193
+ // Surface the error through the callback rather than throwing from
194
+ // an event listener (which would be silently swallowed by ethers)
195
+ console.error('[ArbiLink] watchMessage error:', err);
196
+ }
197
+ };
198
+ this.messageHub.on(confirmedFilter, listener);
199
+ return () => {
200
+ this.messageHub.off(confirmedFilter, listener);
201
+ };
202
+ }
203
+ // ── Relayer helpers ────────────────────────────────────────────────────────
204
+ /**
205
+ * Check whether `address` is a registered, active relayer.
206
+ */
207
+ async isActiveRelayer(address) {
208
+ return await this.messageHub.isActiveRelayer(address);
209
+ }
210
+ /**
211
+ * Register the signer as a relayer by staking the required ETH.
212
+ * Fetches the minimum stake from the hub automatically.
213
+ *
214
+ * @param stakeOverride - Override the minimum stake amount (wei).
215
+ */
216
+ async registerRelayer(stakeOverride) {
217
+ this.requireSigner();
218
+ const stake = stakeOverride ?? await this.messageHub.minStake();
219
+ const tx = await this.messageHub.registerRelayer({ value: stake });
220
+ await tx.wait();
221
+ }
222
+ /**
223
+ * Withdraw the signer's relayer stake and deregister.
224
+ */
225
+ async exitRelayer() {
226
+ this.requireSigner();
227
+ const tx = await this.messageHub.exitRelayer();
228
+ await tx.wait();
229
+ }
230
+ // ── Hub info ───────────────────────────────────────────────────────────────
231
+ /**
232
+ * Total number of messages sent through the hub.
233
+ */
234
+ async messageCount() {
235
+ return await this.messageHub.messageCount();
236
+ }
237
+ /**
238
+ * The hub owner address.
239
+ */
240
+ async owner() {
241
+ return await this.messageHub.owner();
242
+ }
243
+ /**
244
+ * Minimum stake (wei) required to register as a relayer.
245
+ */
246
+ async minStake() {
247
+ return await this.messageHub.minStake();
248
+ }
249
+ // ── Private helpers ────────────────────────────────────────────────────────
250
+ requireSigner() {
251
+ if (!this.signer) {
252
+ throw new types_1.ArbiLinkError('This operation requires a Signer. Initialize ArbiLink with an ethers.Signer instead of a Provider.');
253
+ }
254
+ }
255
+ }
256
+ exports.ArbiLink = ArbiLink;
257
+ //# sourceMappingURL=ArbiLink.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ArbiLink.js","sourceRoot":"","sources":["../src/ArbiLink.ts"],"names":[],"mappings":"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"}