Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion packages/filler-v2/src/tests/filler.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -316,7 +316,7 @@ describe.skip("Filler V2 - Tron Source Chain", () => {
destination: toHex(polygonAmoyId),
deadline: 12545151568145n,
nonce: 0n,
fees: parseUnits("0.005", sourceUsdtDecimals),
fees: 0n,
session: "0x0000000000000000000000000000000000000000" as HexString,
predispatch: { assets: [], call: "0x" as HexString },
inputs,
Expand Down
6 changes: 6 additions & 0 deletions packages/sdk/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# @hyperbridge/sdk

## 1.6.3

### Patch Changes

- Further improvements to intents v2

## 1.6.2

### Patch Changes
Expand Down
2 changes: 1 addition & 1 deletion packages/sdk/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@hyperbridge/sdk",
"version": "1.6.2",
"version": "1.6.3",
"description": "The hyperclient SDK provides utilities for querying proofs and statuses for cross-chain requests from HyperBridge.",
"type": "module",
"types": "./dist/node/index.d.ts",
Expand Down
18 changes: 18 additions & 0 deletions packages/sdk/src/configs/chain.ts
Original file line number Diff line number Diff line change
Expand Up @@ -231,10 +231,12 @@ export const chainConfigs: Record<number, ChainConfigData> = {
DAI: "0x6b175474e89094c44da98b954eedeac495271d0f",
USDC: "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48",
USDT: "0xdac17f958d2ee523a2206206994597c13d831ec7",
cNGN: "0x17CDB2a01e7a34CbB3DD4b83260B05d0274C8dab",
},
tokenDecimals: {
USDC: 6,
USDT: 6,
cNGN: 6,
},
tokenStorageSlots: {
USDT: { balanceSlot: 2, allowanceSlot: 5 },
Expand All @@ -244,6 +246,8 @@ export const chainConfigs: Record<number, ChainConfigData> = {
},
addresses: {
IntentGateway: "0x1a4ee689a004b10210a1df9f24a387ea13359acf",
IntentGatewayV2: "0x2d61624A17f361020679FaA16fbB566C344AaF4B",
SolverAccount: "0xd4d594C99f23b1Fb9d65fdd9062854B1A1C5780b",
TokenGateway: "0xFd413e3AFe560182C4471F4d143A96d3e259B6dE",
Host: "0x792A6236AF69787C40cF76b69B4c8c7B28c4cA20",
UniswapRouter02: "0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D",
Expand Down Expand Up @@ -292,6 +296,8 @@ export const chainConfigs: Record<number, ChainConfigData> = {
},
addresses: {
IntentGateway: "0x1a4ee689a004b10210a1df9f24a387ea13359acf",
IntentGatewayV2: "0x2d61624A17f361020679FaA16fbB566C344AaF4B",
SolverAccount: "0xd4d594C99f23b1Fb9d65fdd9062854B1A1C5780b",
TokenGateway: "0xFd413e3AFe560182C4471F4d143A96d3e259B6dE",
Host: "0x24B5d421Ec373FcA57325dd2F0C074009Af021F7",
UniswapRouter02: "0x10ED43C718714eb63d5aA57B78B54704E256024E",
Expand Down Expand Up @@ -342,6 +348,8 @@ export const chainConfigs: Record<number, ChainConfigData> = {
},
addresses: {
IntentGateway: "0x1a4ee689a004b10210a1df9f24a387ea13359acf",
IntentGatewayV2: "0x2d61624A17f361020679FaA16fbB566C344AaF4B",
SolverAccount: "0xd4d594C99f23b1Fb9d65fdd9062854B1A1C5780b",
TokenGateway: "0xFd413e3AFe560182C4471F4d143A96d3e259B6dE",
Host: "0xE05AFD4Eb2ce6d65c40e1048381BD0Ef8b4B299e",
UniswapRouter02: "0x4752ba5DBc23f44D87826276BF6Fd6b1C372aD24",
Expand Down Expand Up @@ -377,10 +385,12 @@ export const chainConfigs: Record<number, ChainConfigData> = {
DAI: "0x50c5725949a6f0c72e6c4a641f24049a917db0cb",
USDC: "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913",
USDT: "0xfde4c96c8593536e31f229ea8f37b2ada2699bb2",
cNGN: "0x46C85152bFe9f96829aA94755D9f915F9B10EF5F",
},
tokenDecimals: {
USDC: 6,
USDT: 6,
cNGN: 6,
},
tokenStorageSlots: {
USDT: { balanceSlot: 0, allowanceSlot: 1 },
Expand All @@ -390,6 +400,8 @@ export const chainConfigs: Record<number, ChainConfigData> = {
},
addresses: {
IntentGateway: "0x1a4ee689a004b10210a1df9f24a387ea13359acf",
IntentGatewayV2: "0x2d61624A17f361020679FaA16fbB566C344AaF4B",
SolverAccount: "0xd4d594C99f23b1Fb9d65fdd9062854B1A1C5780b",
TokenGateway: "0xFd413e3AFe560182C4471F4d143A96d3e259B6dE",
Host: "0x6FFe92e4d7a9D589549644544780e6725E84b248",
UniswapRouter02: "0x4752ba5DBc23f44D87826276BF6Fd6b1C372aD24",
Expand Down Expand Up @@ -425,10 +437,12 @@ export const chainConfigs: Record<number, ChainConfigData> = {
DAI: "0x8f3cf7ad23cd3cadbd9735aff958023239c6a063",
USDC: "0x3c499c542cef5e3811e1192ce70d8cc03d5c3359",
USDT: "0xc2132d05d31c914a87c6611c10748aeb04b58e8f",
cNGN: "0x52828daa48C1a9A06F37500882b42daf0bE04C3B",
},
tokenDecimals: {
USDC: 6,
USDT: 6,
cNGN: 6,
},
tokenStorageSlots: {
USDT: { balanceSlot: 0, allowanceSlot: 1 },
Expand All @@ -438,6 +452,8 @@ export const chainConfigs: Record<number, ChainConfigData> = {
},
addresses: {
IntentGateway: "0x1a4ee689a004b10210a1df9f24a387ea13359acf",
IntentGatewayV2: "0x2d61624A17f361020679FaA16fbB566C344AaF4B",
SolverAccount: "0xd4d594C99f23b1Fb9d65fdd9062854B1A1C5780b",
TokenGateway: "0x8b536105b6Fae2aE9199f5146D3C57Dfe53b614E",
Host: "0xD8d3db17C1dF65b301D45C84405CcAC1395C559a",
UniswapRouter02: "0xd2f9496824951D5237cC71245D659E48d0d5f9E8",
Expand Down Expand Up @@ -480,6 +496,8 @@ export const chainConfigs: Record<number, ChainConfigData> = {
},
addresses: {
IntentGateway: "0x1a4ee689a004b10210a1df9f24a387ea13359acf",
IntentGatewayV2: "0x2d61624A17f361020679FaA16fbB566C344AaF4B",
SolverAccount: "0xd4d594C99f23b1Fb9d65fdd9062854B1A1C5780b",
TokenGateway: "0x8b536105b6Fae2aE9199f5146D3C57Dfe53b614E",
Host: "0x2A17C1c3616Bbc33FCe5aF5B965F166ba76cEDAf",
UniswapRouter02: "0x284f11109359a7e1306c3e447ef14d38400063ff",
Expand Down
28 changes: 14 additions & 14 deletions packages/sdk/src/protocols/intentsV2/GasEstimator.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { encodeFunctionData, toHex, pad, maxUint256, concat, keccak256 } from "viem"
import { encodeFunctionData, toHex, pad, maxUint256, concat, keccak256, isHex, hexToString } from "viem"
import { generatePrivateKey, privateKeyToAccount, privateKeyToAddress } from "viem/accounts"
import { ABI as IntentGatewayV2ABI } from "@/abis/IntentGatewayV2"
import IntentGateway from "@/abis/IntentGateway"
Expand Down Expand Up @@ -41,11 +41,11 @@ export class GasEstimator {
const { order } = params
const solverPrivateKey = generatePrivateKey()
const solverAccountAddress = privateKeyToAddress(solverPrivateKey)
const intentGatewayV2Address = this.ctx.dest.configService.getIntentGatewayV2Address(order.destination)
const entryPointAddress = this.ctx.dest.configService.getEntryPointV08Address(order.destination)
const chainId = BigInt(
this.ctx.dest.client.chain?.id ?? Number.parseInt(this.ctx.dest.config.stateMachineId.split("-")[1]),
)
const souceStateMachineId = isHex(order.source) ? hexToString(order.source) : order.source
const destStateMachineId = isHex(order.destination) ? hexToString(order.destination) : order.destination
const intentGatewayV2Address = this.ctx.dest.configService.getIntentGatewayV2Address(destStateMachineId)
const entryPointAddress = this.ctx.dest.configService.getEntryPointV08Address(destStateMachineId)
const chainId = BigInt(Number.parseInt(destStateMachineId.split("-")[1]))

const totalEthValue = order.output.assets
.filter((output) => bytes32ToBytes20(output.token) === ADDRESS_ZERO)
Expand All @@ -61,14 +61,14 @@ export class GasEstimator {

const { viem: stateOverrides, bundler: bundlerStateOverrides } = await this.buildStateOverride({
accountAddress: solverAccountAddress,
chain: order.destination,
chain: destStateMachineId,
outputAssets: assetsForOverrides,
spenderAddress: intentGatewayV2Address,
intentGatewayV2Address,
entryPointAddress,
})

const isSameChain = order.source === order.destination
const isSameChain = souceStateMachineId === destStateMachineId
let postRequestFeeInDestFeeToken = 0n
let protocolFeeInNativeToken = 0n

Expand All @@ -78,7 +78,7 @@ export class GasEstimator {
this.ctx,
postRequestGas,
"source",
order.source,
souceStateMachineId,
)
postRequestFeeInDestFeeToken = adjustDecimals(
postRequestFeeInSourceFeeToken,
Expand All @@ -87,13 +87,13 @@ export class GasEstimator {
)

const postRequest: IPostRequest = {
source: order.destination,
dest: order.source,
source: destStateMachineId,
dest: souceStateMachineId,
body: constructRedeemEscrowRequestBody({ ...order, id: orderV2Commitment(order) }, MOCK_ADDRESS),
timeoutTimestamp: 0n,
nonce: await this.ctx.source.getHostNonce(),
from: this.ctx.source.configService.getIntentGatewayV2Address(order.destination),
to: this.ctx.source.configService.getIntentGatewayV2Address(order.source),
from: this.ctx.source.configService.getIntentGatewayV2Address(destStateMachineId),
to: this.ctx.source.configService.getIntentGatewayV2Address(souceStateMachineId),
}

protocolFeeInNativeToken = await this.quoteNative(postRequest, postRequestFeeInDestFeeToken).catch(() =>
Expand Down Expand Up @@ -216,7 +216,7 @@ export class GasEstimator {
this.ctx,
totalGas,
"dest",
order.destination,
destStateMachineId,
gasPrice,
)
const totalGasInSourceFeeToken = adjustDecimals(
Expand Down
11 changes: 11 additions & 0 deletions packages/sdk/src/protocols/intentsV2/IntentsV2.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import { OrderExecutor } from "./OrderExecutor"
import { OrderCanceller } from "./OrderCanceller"
import { BidManager } from "./BidManager"
import { GasEstimator } from "./GasEstimator"
import { OrderStatusChecker } from "./OrderStatusChecker"
import type { ERC7821Call } from "@/types"
import { DEFAULT_GRAFFITI } from "@/utils"

Expand All @@ -41,6 +42,7 @@ export class IntentsV2 {
private readonly orderPlacer: OrderPlacer
private readonly orderExecutor: OrderExecutor
private readonly orderCanceller: OrderCanceller
private readonly orderStatusChecker: OrderStatusChecker
private readonly bidManager: BidManager
private readonly gasEstimator: GasEstimator

Expand Down Expand Up @@ -80,6 +82,7 @@ export class IntentsV2 {
this.orderPlacer = new OrderPlacer(this.ctx)
this.orderExecutor = new OrderExecutor(this.ctx, bidManager)
this.orderCanceller = new OrderCanceller(this.ctx)
this.orderStatusChecker = new OrderStatusChecker(this.ctx)
this.bidManager = bidManager
this.gasEstimator = gasEstimator
this._crypto = crypto
Expand Down Expand Up @@ -217,4 +220,12 @@ export class IntentsV2 {
decodeERC7821Execute(callData: HexString): ERC7821Call[] | null {
return this._crypto.decodeERC7821Execute(callData)
}

async isOrderFilled(order: OrderV2): Promise<boolean> {
return this.orderStatusChecker.isOrderFilled(order)
}

async isOrderRefunded(order: OrderV2): Promise<boolean> {
return this.orderStatusChecker.isOrderRefunded(order)
}
}
79 changes: 79 additions & 0 deletions packages/sdk/src/protocols/intentsV2/OrderStatusChecker.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import { isHex, hexToString } from "viem"
import { ABI as IntentGatewayV2ABI } from "@/abis/IntentGatewayV2"
import { orderV2Commitment, bytes32ToBytes20 } from "@/utils"
import type { OrderV2, HexString } from "@/types"
import type { IntentsV2Context } from "./types"

export class OrderStatusChecker {
constructor(private readonly ctx: IntentsV2Context) {}

/**
* Checks if a V2 order has been filled by reading the commitment storage slot on the destination chain.
*
* Reads the storage slot returned by `calculateCommitmentSlotHash` on the IntentGatewayV2 contract.
* A non-zero value at that slot means the solver has called `fillOrder` and the order is complete
* from the user's perspective (the beneficiary has received their tokens).
*
* @param order - The V2 order to check. `order.id` is used as the commitment; if not set it is computed.
* @returns True if the order has been filled on the destination chain, false otherwise.
*/
async isOrderFilled(order: OrderV2): Promise<boolean> {
const commitment = (order.id ?? orderV2Commitment(order)) as HexString
const destStateMachineId = isHex(order.destination)
? hexToString(order.destination as HexString)
: order.destination

const intentGatewayV2Address = this.ctx.dest.configService.getIntentGatewayV2Address(destStateMachineId)

const filledSlot = await this.ctx.dest.client.readContract({
abi: IntentGatewayV2ABI,
address: intentGatewayV2Address,
functionName: "calculateCommitmentSlotHash",
args: [commitment],
})

const filledStatus = await this.ctx.dest.client.getStorageAt({
address: intentGatewayV2Address,
slot: filledSlot as HexString,
})

return filledStatus !== "0x0000000000000000000000000000000000000000000000000000000000000000"
}

/**
* Checks if a V2 order has been refunded by reading the `_orders` mapping on the source chain.
*
* Calls `_orders(commitment, tokenAddress)` for each input token. When the order is placed the
* escrowed amounts are stored there. After a successful refund the contract zeroes them out.
* An order is considered refunded when all escrowed input amounts have been returned (i.e. are 0).
*
* @param order - The V2 order to check. `order.id` is used as the commitment; if not set it is computed.
* @returns True if all escrowed inputs have been returned to the user on the source chain, false otherwise.
*/
async isOrderRefunded(order: OrderV2): Promise<boolean> {
if (!order.inputs || order.inputs.length === 0) return false

const commitment = (order.id ?? orderV2Commitment(order)) as HexString
const sourceStateMachineId = isHex(order.source)
? hexToString(order.source as HexString)
: order.source

const intentGatewayV2Address = this.ctx.source.configService.getIntentGatewayV2Address(sourceStateMachineId)

for (const input of order.inputs) {
const tokenAddress = bytes32ToBytes20(input.token)
const escrowedAmount = await this.ctx.source.client.readContract({
abi: IntentGatewayV2ABI,
address: intentGatewayV2Address,
functionName: "_orders",
args: [commitment, tokenAddress],
})

if (escrowedAmount !== 0n) {
return false
}
}

return true
}
}
1 change: 1 addition & 0 deletions packages/sdk/src/protocols/intentsV2/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export { IntentsV2 } from "./IntentsV2"
export { OrderStatusChecker } from "./OrderStatusChecker"
export { encodeERC7821ExecuteBatch, transformOrderForContract, fetchSourceProof } from "./utils"
export { SELECT_SOLVER_TYPEHASH, PACKED_USEROP_TYPEHASH, DOMAIN_TYPEHASH } from "./CryptoUtils"
export {
Expand Down
Loading