@hyperbridge/sdk 2.0.0 → 2.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/README.md +172 -78
- package/dist/browser/index.d.ts +3182 -1944
- package/dist/browser/index.js +16904 -15038
- package/dist/browser/index.js.map +1 -1
- package/dist/node/index.cjs +21719 -0
- package/dist/node/index.cjs.map +1 -0
- package/dist/node/index.d.cts +9909 -0
- package/dist/node/index.d.ts +3182 -1944
- package/dist/node/index.js +16901 -15035
- package/dist/node/index.js.map +1 -1
- package/package.json +8 -5
package/README.md
CHANGED
|
@@ -141,103 +141,195 @@ const hyperbridge = new SubstrateChain({
|
|
|
141
141
|
const proof = await hyperbridge.queryStateProof(blockNumber, keys)
|
|
142
142
|
```
|
|
143
143
|
|
|
144
|
-
###
|
|
144
|
+
### HyperFungibleToken - Cross-Chain Token Transfers
|
|
145
145
|
|
|
146
|
-
The
|
|
146
|
+
The `HyperFungibleToken` class provides a generator-based flow for bridging tokens cross-chain via Hyperbridge. It supports both `HyperFungibleToken` (burn/mint) and `WrappedHyperFungibleToken` (lock/unlock) contracts, with automatic type detection via ERC165.
|
|
147
|
+
|
|
148
|
+
#### Setup
|
|
147
149
|
|
|
148
150
|
```ts
|
|
149
|
-
import {
|
|
150
|
-
|
|
151
|
+
import {
|
|
152
|
+
HyperFungibleToken,
|
|
153
|
+
IsmpClient,
|
|
154
|
+
createQueryClient,
|
|
155
|
+
EvmChain,
|
|
156
|
+
SubstrateChain
|
|
157
|
+
} from "@hyperbridge/sdk"
|
|
158
|
+
import { parseEther } from "viem"
|
|
159
|
+
|
|
160
|
+
// EvmChain.create auto-detects chain ID and resolves the IsmpHost address
|
|
161
|
+
const source = await EvmChain.create("https://data-seed-prebsc-1-s1.binance.org:8545")
|
|
162
|
+
const dest = await EvmChain.create("https://rpc-amoy.polygon.technology")
|
|
163
|
+
|
|
164
|
+
const hft = new HyperFungibleToken({ source, dest })
|
|
165
|
+
```
|
|
151
166
|
|
|
152
|
-
|
|
153
|
-
const sourceChain = new EvmChain({
|
|
154
|
-
chainId: 97, // BSC Testnet
|
|
155
|
-
rpcUrl: "https://data-seed-prebsc-1-s1.binance.org:8545",
|
|
156
|
-
host: "0x...", // IsmpHost contract address
|
|
157
|
-
consensusStateId: "BSC0"
|
|
158
|
-
})
|
|
167
|
+
#### Detect Token Type
|
|
159
168
|
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
consensusStateId: "GNO0"
|
|
165
|
-
})
|
|
169
|
+
```ts
|
|
170
|
+
/* Returns true for WrappedHyperFungibleToken contracts (ERC165) */
|
|
171
|
+
const isWrapped = await hft.isWrapped(tokenAddress)
|
|
172
|
+
```
|
|
166
173
|
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
174
|
+
#### Quote Fees
|
|
175
|
+
|
|
176
|
+
```ts
|
|
177
|
+
const fee = await hft.quote({
|
|
178
|
+
token: "0x...", // HFT or WrappedHFT contract address
|
|
179
|
+
from: senderAddress,
|
|
180
|
+
to: recipientAddress, // 20-byte EVM or 32-byte substrate address
|
|
181
|
+
amount: parseEther("100"),
|
|
182
|
+
dest: "EVM-80002", // Destination state machine ID
|
|
171
183
|
})
|
|
172
184
|
|
|
173
|
-
//
|
|
174
|
-
|
|
175
|
-
|
|
185
|
+
console.log(fee.totalNativeCost) // msg.value needed (native token)
|
|
186
|
+
console.log(fee.totalFeeTokenCost) // equivalent in host fee token
|
|
187
|
+
console.log(fee.relayerFeeInFeeToken) // relayer fee component
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
Fee estimation works by:
|
|
191
|
+
1. Estimating gas cost for message delivery on the destination chain
|
|
192
|
+
2. Converting dest gas cost to dest fee token via Uniswap
|
|
193
|
+
3. Scaling decimals between source and dest fee tokens
|
|
194
|
+
4. Calling the on-chain `quote()` / `quoteNative()` methods
|
|
195
|
+
|
|
196
|
+
#### Bridge Tokens
|
|
197
|
+
|
|
198
|
+
The `bridge()` method returns an async generator that yields steps for the caller to execute:
|
|
176
199
|
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
200
|
+
```ts
|
|
201
|
+
const gen = hft.bridge({
|
|
202
|
+
token: "0x...",
|
|
203
|
+
from: account.address,
|
|
181
204
|
to: recipientAddress,
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
205
|
+
amount: parseEther("1"),
|
|
206
|
+
dest: "EVM-80002",
|
|
207
|
+
timeout: 3600n, // optional, default 3600s
|
|
208
|
+
payInFeeToken: false, // optional, default false (pay in native)
|
|
209
|
+
relayerFee: undefined, // optional, override relayer fee (0n for self-relay)
|
|
210
|
+
})
|
|
211
|
+
|
|
212
|
+
let result = await gen.next()
|
|
213
|
+
|
|
214
|
+
while (!result.done) {
|
|
215
|
+
const step = result.value
|
|
216
|
+
|
|
217
|
+
if (step.type === "approve") {
|
|
218
|
+
/* ERC20 approval needed (WrappedHFT or feeToken) */
|
|
219
|
+
const hash = await walletClient.sendTransaction({
|
|
220
|
+
to: step.tx.to,
|
|
221
|
+
data: step.tx.data,
|
|
222
|
+
})
|
|
223
|
+
await publicClient.waitForTransactionReceipt({ hash })
|
|
224
|
+
result = await gen.next()
|
|
225
|
+
continue
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
if (step.type === "send") {
|
|
229
|
+
/* The cross-chain send transaction */
|
|
230
|
+
const hash = await walletClient.sendTransaction({
|
|
231
|
+
to: step.tx.to,
|
|
232
|
+
data: step.tx.data,
|
|
233
|
+
value: step.tx.value,
|
|
234
|
+
})
|
|
235
|
+
result = await gen.next(hash) // resume with tx hash
|
|
236
|
+
continue
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
if (step.type === "submitted") {
|
|
240
|
+
console.log("Commitment:", step.commitment)
|
|
241
|
+
result = await gen.next()
|
|
242
|
+
continue
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
if (step.type === "status") {
|
|
246
|
+
console.log("Status:", step.status)
|
|
247
|
+
/* Statuses: SOURCE_FINALIZED → HYPERBRIDGE_DELIVERED →
|
|
248
|
+
HYPERBRIDGE_FINALIZED → DESTINATION */
|
|
249
|
+
if (step.status === "DESTINATION") break
|
|
250
|
+
result = await gen.next()
|
|
251
|
+
continue
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
result = await gen.next()
|
|
185
255
|
}
|
|
256
|
+
```
|
|
186
257
|
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
wsUrl: "wss://gargantua.polytope.technology",
|
|
258
|
+
#### Generator Steps
|
|
259
|
+
|
|
260
|
+
| Step | Description |
|
|
261
|
+
|------|-------------|
|
|
262
|
+
| `approve` | ERC20 approval tx. Yielded for WrappedHFT (underlying token) or when `payInFeeToken` is true (fee token). Only if current allowance is insufficient. |
|
|
263
|
+
| `send` | The cross-chain send tx. Resume the generator with the submitted tx hash. |
|
|
264
|
+
| `submitted` | Emitted after the send tx is mined. Contains the ISMP `commitment` hash. |
|
|
265
|
+
| `status` | ISMP request lifecycle updates. Only yielded if `client` was provided. |
|
|
266
|
+
|
|
267
|
+
#### Tracking with IsmpClient
|
|
268
|
+
|
|
269
|
+
To receive status updates after submission, provide an `IsmpClient`:
|
|
270
|
+
|
|
271
|
+
```ts
|
|
272
|
+
const hyperbridge = await SubstrateChain.connect({
|
|
273
|
+
wsUrl: "wss://gargantua.rpc.polytope.technology",
|
|
274
|
+
consensusStateId: "PAS0",
|
|
203
275
|
hasher: "Keccak",
|
|
204
|
-
|
|
276
|
+
stateMachineId: "KUSAMA-4009",
|
|
205
277
|
})
|
|
206
278
|
|
|
207
|
-
const
|
|
208
|
-
|
|
209
|
-
dest: substrateDestChain // SubstrateChain destination
|
|
279
|
+
const queryClient = createQueryClient({
|
|
280
|
+
url: "https://gargantua.indexer.polytope.technology",
|
|
210
281
|
})
|
|
211
282
|
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
283
|
+
const ismpClient = new IsmpClient({
|
|
284
|
+
queryClient,
|
|
285
|
+
source,
|
|
286
|
+
dest,
|
|
287
|
+
hyperbridge,
|
|
288
|
+
pollInterval: 5_000,
|
|
289
|
+
})
|
|
290
|
+
|
|
291
|
+
const hft = new HyperFungibleToken({ source, dest, client: ismpClient })
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
Without `client`, the generator terminates after the `submitted` step.
|
|
295
|
+
|
|
296
|
+
#### Self-Relay
|
|
224
297
|
|
|
225
|
-
|
|
226
|
-
const erc20Address = await tokenGateway.getErc20Address(assetId)
|
|
227
|
-
const erc6160Address = await tokenGateway.getErc6160Address(assetId)
|
|
298
|
+
Set `relayerFee: 0n` and handle the `HYPERBRIDGE_FINALIZED` status to submit the proof calldata yourself:
|
|
228
299
|
|
|
229
|
-
|
|
230
|
-
const
|
|
231
|
-
|
|
300
|
+
```ts
|
|
301
|
+
const gen = hft.bridge({
|
|
302
|
+
token: "0x...",
|
|
303
|
+
from: account.address,
|
|
304
|
+
to: account.address,
|
|
305
|
+
amount: parseEther("1"),
|
|
306
|
+
dest: "EVM-80002",
|
|
307
|
+
relayerFee: 0n,
|
|
308
|
+
payInFeeToken: true,
|
|
309
|
+
})
|
|
310
|
+
|
|
311
|
+
/* ... handle approve/send/submitted steps ... */
|
|
312
|
+
|
|
313
|
+
if (step.type === "status" && step.status === "HYPERBRIDGE_FINALIZED") {
|
|
314
|
+
const { calldata } = step.metadata
|
|
315
|
+
/* Submit calldata to the dest chain's handler contract */
|
|
316
|
+
const hostParams = await destPublicClient.readContract({
|
|
317
|
+
address: destHostAddress,
|
|
318
|
+
abi: evmHostABI,
|
|
319
|
+
functionName: "hostParams",
|
|
320
|
+
})
|
|
321
|
+
await destWalletClient.sendTransaction({
|
|
322
|
+
to: hostParams.handler,
|
|
323
|
+
data: calldata,
|
|
324
|
+
})
|
|
325
|
+
}
|
|
232
326
|
```
|
|
233
327
|
|
|
234
|
-
**
|
|
328
|
+
**HyperFungibleToken Methods:**
|
|
235
329
|
|
|
236
|
-
- `
|
|
237
|
-
- `
|
|
238
|
-
- `
|
|
239
|
-
- `getInstanceAddress(destination)` - Get the TokenGateway address on the destination chain
|
|
240
|
-
- `getParams()` - Get the TokenGateway contract parameters (host and dispatcher addresses)
|
|
330
|
+
- `isWrapped(tokenAddress)` - Detect whether a token is a WrappedHyperFungibleToken via ERC165
|
|
331
|
+
- `quote(params)` - Quote the cross-chain fee. Returns `{ totalNativeCost, totalFeeTokenCost, relayerFeeInFeeToken }`
|
|
332
|
+
- `bridge(params)` - Async generator that yields `approve`, `send`, `submitted`, and `status` steps
|
|
241
333
|
|
|
242
334
|
## Vite Integration
|
|
243
335
|
|
|
@@ -268,18 +360,20 @@ The plugin automatically copies the necessary WebAssembly files to the correct l
|
|
|
268
360
|
### Classes
|
|
269
361
|
|
|
270
362
|
- **IsmpClient** - Main client for tracking ISMP requests via the indexer
|
|
363
|
+
- **HyperFungibleToken** - Generator-based cross-chain token bridging with fee quoting and ISMP status tracking
|
|
271
364
|
- **IntentGateway** - Cross-chain intent order placement and status tracking (pair with `withQueryClient(queryClient)` for indexer-backed order status)
|
|
272
|
-
- **TokenGateway** - Cross-chain token transfers and teleport status tracking (pair with `withQueryClient(queryClient)` for indexer-backed teleport status)
|
|
273
365
|
- **EvmChain** - Utilities for EVM chain interaction
|
|
274
366
|
- **SubstrateChain** - Utilities for Substrate chain interaction
|
|
275
|
-
- **TokenGateway** - Utilities for cross-chain token transfers and fee estimation
|
|
276
367
|
|
|
277
368
|
### Types
|
|
278
369
|
|
|
279
370
|
- RequestStatus - Enum of possible request statuses
|
|
280
371
|
- TimeoutStatus - Enum of possible timeout statuses
|
|
372
|
+
- BridgeParams - Parameters for `HyperFungibleToken.bridge()` and `quote()`
|
|
373
|
+
- BridgeStep - Union type yielded by the bridge generator
|
|
374
|
+
- QuoteResult - Fee quote returned by `HyperFungibleToken.quote()`
|
|
281
375
|
- HexString - Type for hex-encoded strings
|
|
282
376
|
|
|
283
377
|
### Examples
|
|
284
378
|
|
|
285
|
-
See the tests [
|
|
379
|
+
See the [HyperFungibleToken tests](/packages/sdk/src/tests/hyperFungibleToken.test.ts) and [request tracking tests](/packages/sdk/src/tests/sequential/requests.test.ts) for complete examples.
|