Skip to content

Commit 784bd7d

Browse files
authored
fix(api): throw if recipient or app fee recipient not initialized on HyperCore (#1865)
1 parent 45a3965 commit 784bd7d

File tree

3 files changed

+63
-1
lines changed

3 files changed

+63
-1
lines changed

api/_bridges/hypercore/strategy.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import { CHAIN_IDs, TOKEN_SYMBOLS_MAP } from "../../_constants";
1515
import { InvalidParamError } from "../../_errors";
1616
import { encodeTransferCalldata } from "../../_multicall-handler";
1717
import { tagIntegratorId, tagSwapApiMarker } from "../../_integrator-id";
18+
import { accountExistsOnHyperCore } from "../../_hypercore";
1819

1920
const supportedTokens = [TOKEN_SYMBOLS_MAP["USDT-SPOT"]];
2021

@@ -198,6 +199,16 @@ export function getHyperCoreBridgeStrategy(): BridgeStrategy {
198199
});
199200
}
200201

202+
const depositorExists = await accountExistsOnHyperCore({
203+
account: crossSwap.depositor,
204+
});
205+
206+
if (!depositorExists) {
207+
throw new InvalidParamError({
208+
message: "Depositor is not initialized on HyperCore",
209+
});
210+
}
211+
201212
const data = encodeTransferCalldata(
202213
crossSwap.outputToken.address, // System address on HyperCore
203214
bridgeQuote.inputAmount // in HyperEVM decimals

api/_dexes/cross-swap-service.ts

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,9 @@ import {
4646
} from "./types";
4747
import { BridgeStrategy } from "../_bridges/types";
4848
import { getSpokePoolPeripheryAddress } from "../_spoke-pool-periphery";
49+
import { accountExistsOnHyperCore } from "../_hypercore";
50+
import { CHAIN_IDs } from "../_constants";
51+
import { BigNumber } from "ethers";
4952

5053
const QUOTE_BUFFER = 0.005; // 0.5%
5154

@@ -247,6 +250,33 @@ export async function getCrossSwapQuotesForExactInputB2BI(
247250
indirectDestinationRoute.intermediaryOutputToken.decimals
248251
)(crossSwap.amount);
249252

253+
// If destination chain is HyperCore, we need to check if the app fee recipient and recipient
254+
// have initialized balances on HyperCore.
255+
if (crossSwap.outputToken.chainId === CHAIN_IDs.HYPERCORE) {
256+
const [appFeeRecipientExists, recipientExists] = await Promise.all([
257+
crossSwap.appFeeRecipient
258+
? accountExistsOnHyperCore({
259+
account: crossSwap.appFeeRecipient,
260+
})
261+
: BigNumber.from(0),
262+
accountExistsOnHyperCore({
263+
account: crossSwap.recipient,
264+
}),
265+
]);
266+
267+
if (crossSwap.appFeeRecipient && !appFeeRecipientExists) {
268+
throw new InvalidParamError({
269+
message: "App fee recipient is not initialized on HyperCore",
270+
});
271+
}
272+
273+
if (!recipientExists) {
274+
throw new InvalidParamError({
275+
message: "Recipient is not initialized on HyperCore",
276+
});
277+
}
278+
}
279+
250280
// 1. We fetch a quote from inputToken.chainId -> intermediaryOutputToken.chainId
251281
const { bridgeQuote } = await bridge.getQuoteForExactInput({
252282
inputToken: crossSwap.inputToken,

api/_hypercore.ts

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@ import { CHAIN_IDs } from "./_constants";
77
export const CORE_BALANCE_SYSTEM_PRECOMPILE =
88
"0x0000000000000000000000000000000000000801";
99

10+
// Contract used to check if an account exists on Hypercore.
11+
export const CORE_USER_EXISTS_PRECOMPILE_ADDRESS =
12+
"0x0000000000000000000000000000000000000810";
13+
1014
// CoreWriter contract on EVM that can be used to interact with Hypercore.
1115
export const CORE_WRITER_EVM_ADDRESS =
1216
"0x3333333333333333333333333333333333333333";
@@ -67,7 +71,7 @@ export async function getBalanceOnHyperCore(params: {
6771
account: string;
6872
tokenSystemAddress: string;
6973
}) {
70-
const provider = getProvider(CHAIN_IDs.HYPERCORE);
74+
const provider = getProvider(CHAIN_IDs.HYPEREVM);
7175
const tokenIndex = parseInt(
7276
params.tokenSystemAddress.replace("0x20", ""),
7377
16
@@ -86,3 +90,20 @@ export async function getBalanceOnHyperCore(params: {
8690
);
8791
return BigNumber.from(decodedQueryResult[0].toString());
8892
}
93+
94+
export async function accountExistsOnHyperCore(params: { account: string }) {
95+
const provider = getProvider(CHAIN_IDs.HYPEREVM);
96+
const balanceCoreCalldata = ethers.utils.defaultAbiCoder.encode(
97+
["address"],
98+
[params.account]
99+
);
100+
const queryResult = await provider.call({
101+
to: CORE_USER_EXISTS_PRECOMPILE_ADDRESS,
102+
data: balanceCoreCalldata,
103+
});
104+
const decodedQueryResult = ethers.utils.defaultAbiCoder.decode(
105+
["bool"],
106+
queryResult
107+
);
108+
return Boolean(decodedQueryResult[0]);
109+
}

0 commit comments

Comments
 (0)