@hyperbridge/sdk 2.0.1 → 2.2.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 CHANGED
@@ -141,103 +141,195 @@ const hyperbridge = new SubstrateChain({
141
141
  const proof = await hyperbridge.queryStateProof(blockNumber, keys)
142
142
  ```
143
143
 
144
- ### TokenGateway - Cross-Chain Token Transfers
144
+ ### HyperFungibleToken - Cross-Chain Token Transfers
145
145
 
146
- The TokenGateway class provides methods for estimating fees and managing cross-chain token teleports via Hyperbridge. Supports both EVM and Substrate chains as destination.
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 { TokenGateway, EvmChain, SubstrateChain } from "@hyperbridge/sdk"
150
- import { keccak256, toHex, pad, parseEther } from "viem"
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
- // Create chain instances
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
- const destChain = new EvmChain({
161
- chainId: 10200, // Gnosis Chiado
162
- rpcUrl: "https://rpc.chiadochain.net",
163
- host: "0x...", // IsmpHost contract address
164
- consensusStateId: "GNO0"
165
- })
169
+ ```ts
170
+ /* Returns true for WrappedHyperFungibleToken contracts (ERC165) */
171
+ const isWrapped = await hft.isWrapped(tokenAddress)
172
+ ```
166
173
 
167
- // Initialize TokenGateway (destination can be EvmChain or SubstrateChain)
168
- const tokenGateway = new TokenGateway({
169
- source: sourceChain,
170
- dest: destChain // EvmChain or SubstrateChain
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
- // Estimate fees for a teleport
174
- const assetId = keccak256(toHex("USDC")) // Asset identifier
175
- const recipientAddress = pad("0xRecipientAddress", { size: 32 })
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
- const teleportParams = {
178
- amount: parseEther("100"), // Amount to teleport
179
- assetId: assetId,
180
- redeem: true, // Redeem as ERC20 on destination
200
+ ```ts
201
+ const gen = hft.bridge({
202
+ token: "0x...",
203
+ from: account.address,
181
204
  to: recipientAddress,
182
- dest: "EVM-10200", // Destination chain
183
- timeout: 3600n, // Timeout in seconds
184
- data: "0x" // Optional call data
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
- // Get native cost estimate (protocol + relayer fees)
188
- // For EVM destination chains, the relayer fee is automatically estimated by:
189
- // 1. Creating a dummy post request with 191 bytes of random data
190
- // 2. Estimating gas for delivery on the destination chain
191
- // 3. Converting gas cost to native tokens and adding 1% buffer
192
- // 4. Converting relayer fee to source fee token using getAmountsOut
193
- // For Substrate destination chains, relayer fee is set to zero
194
- // Returns: totalNativeCost (protocol fee with 1% buffer) and relayerFeeInSourceFeeToken
195
- const { totalNativeCost, relayerFeeInSourceFeeToken } = await tokenGateway.quoteNative(teleportParams)
196
- console.log(`Total native cost: ${totalNativeCost} wei`)
197
- console.log(`Relayer fee in fee token: ${relayerFeeInSourceFeeToken}`)
198
-
199
- // Example with Substrate destination
200
- const substrateDestChain = new SubstrateChain({
201
- stateMachineId: "KUSAMA-4009",
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
- consensusStateId: "PAS0"
276
+ stateMachineId: "KUSAMA-4009",
205
277
  })
206
278
 
207
- const tokenGatewayToSubstrate = new TokenGateway({
208
- source: sourceChain,
209
- dest: substrateDestChain // SubstrateChain destination
279
+ const queryClient = createQueryClient({
280
+ url: "https://gargantua.indexer.polytope.technology",
210
281
  })
211
282
 
212
- // For Substrate destinations, relayer fee will be 0
213
- const { totalNativeCost: substrateCost, relayerFeeInSourceFeeToken: substrateRelayerFee } =
214
- await tokenGatewayToSubstrate.quoteNative({
215
- amount: parseEther("100"),
216
- assetId: assetId,
217
- redeem: true,
218
- to: recipientAddress,
219
- dest: "KUSAMA-4009",
220
- timeout: 3600n
221
- })
222
- console.log(`Substrate destination - Native cost: ${substrateCost} wei`)
223
- console.log(`Substrate destination - Relayer fee: ${substrateRelayerFee}`) // Will be 0
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
- // Get token addresses
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
- // Get gateway parameters
230
- const params = await tokenGateway.getParams()
231
- console.log(`Host: ${params.host}, Dispatcher: ${params.dispatcher}`)
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
- **TokenGateway Methods:**
328
+ **HyperFungibleToken Methods:**
235
329
 
236
- - `quoteNative(params)` - Estimate native token cost for a teleport operation. For EVM destination chains, the relayer fee is automatically estimated by generating a dummy post request with 191 bytes of random data, estimating gas on the destination chain, converting to native tokens, and adding a 1% buffer to the relayer fee. The relayer fee is then converted to source chain fee token using Uniswap V2's `getAmountsOut`. For Substrate destinations, relayer fee is set to zero. Returns an object with `totalNativeCost` (relayer fee + protocol fee, both with 1% buffers) and `relayerFeeInSourceFeeToken` (relayer fee converted to source chain fee token).
237
- - `getErc20Address(assetId)` - Get the ERC20 contract address for an asset
238
- - `getErc6160Address(assetId)` - Get the ERC6160 (hyper-fungible) contract address for an asset
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 [directory](/packages/sdk/src/tests/postRequest.test.ts) for complete examples.
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.