Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/get tx status #7

Merged
merged 10 commits into from
Sep 10, 2024
Merged
Show file tree
Hide file tree
Changes from 4 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
26 changes: 16 additions & 10 deletions apps/example/scripts/sdk.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,21 @@ import {
parseEther,
} from "viem";
import { privateKeyToAccount } from "viem/accounts";
import { arbitrum } from "viem/chains";
import { arbitrum, mainnet } from "viem/chains";
import { loadEnvConfig } from "@next/env";

const projectDir = process.cwd();
loadEnvConfig(projectDir);

// test using client with node
(async function main() {
async function main() {
const chains = [mainnet, arbitrum];

const publicClient = createPublicClient({
chain: arbitrum,
transport: http(),
});

const account = privateKeyToAccount(process.env.DEV_PK as Hex);
const walletClient = createWalletClient({
account,
Expand All @@ -30,24 +33,27 @@ loadEnvConfig(projectDir);
});

const client = AcrossClient.create({
chains,
useTestnet: false,
integratorId: "TEST",
});

console.log(client);

// available routes
const routes = await client.actions.getAvailableRoutes({
originChainId: 42161,
destinationChainId: 1,
originChainId: arbitrum.id,
destinationChainId: mainnet.id,
})!;

/* --------------------------- test normal bridge --------------------------- */
console.log("Testing normal bridge...");
const bridgeRoute = routes.find((r) => r.inputTokenSymbol === "ETH")!;
console.log("Using route:", bridgeRoute);
const route = routes.find((r) => r.inputTokenSymbol === "ETH")!;
console.log("Using route:", route);

// 1. get quote
const bridgeQuoteRes = await client.actions.getQuote({
...bridgeRoute,
route,
inputAmount: parseEther("0.01"),
recipient: account.address,
});
Expand All @@ -56,7 +62,6 @@ loadEnvConfig(projectDir);
// 2. simulate/prep deposit tx
const { request } = await client.actions.simulateDepositTx({
walletClient,
publicClient,
deposit: bridgeQuoteRes.deposit,
});
console.log("Simulation result:", request);
Expand Down Expand Up @@ -89,7 +94,7 @@ loadEnvConfig(projectDir);
const aaveReferralCode = 0;

const quoteRes = await client.actions.getQuote({
...crossChainRoute,
route: crossChainRoute,
inputAmount,
recipient: "0x924a9f036260DdD5808007E1AA95f08eD08aA569",
crossChainMessage: {
Expand Down Expand Up @@ -129,7 +134,8 @@ loadEnvConfig(projectDir);
},
});
console.log(quoteRes);
})();
}
main();

function generateApproveCallData({
aaveAddress,
Expand Down
1 change: 1 addition & 0 deletions packages/sdk/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
"@across-toolkit/eslint-config": "workspace:*",
"@across-toolkit/typescript-config": "workspace:*",
"@arethetypeswrong/cli": "^0.15.4",
"@total-typescript/ts-reset": "^0.6.0",
"@types/node": "^20",
"eslint": "^8.57.0",
"prettier": "^3.2.5",
Expand Down
File renamed without changes.
39 changes: 22 additions & 17 deletions packages/sdk/src/actions/getAvailableRoutes.ts
Original file line number Diff line number Diff line change
@@ -1,33 +1,28 @@
import { Address } from "viem";
import { buildSearchParams, fetchAcross } from "../utils";
import { getClient } from "../client";
import { Route } from "../types";

export type AvailableRoutesParams = Partial<{
export type GetAvailableRoutesParams = Partial<{
originToken: Address;
destinationToken: Address;
destinationChainId: number;
originChainId: number;
}>;
}> & {
apiUrl: string;
};

export type AvailableRoutesResponse = {
originChainId: number;
originToken: string;
destinationChainId: number;
destinationToken: string;
originTokenSymbol: string;
destinationTokenSymbol: string;
isNative: boolean;
}[];

export async function getAvailableRoutes(params?: AvailableRoutesParams) {
const client = getClient();
export type AvailableRoutesResponse = Route[];

export async function getAvailableRoutes(
params: GetAvailableRoutesParams,
): Promise<AvailableRoutesResponse> {
const searchParams = params ? buildSearchParams(params) : "";

const res = await fetchAcross(
`${client.apiUrl}/available-routes?${searchParams}`,
`${params.apiUrl}/available-routes?${searchParams}`,
gsteenkamp89 marked this conversation as resolved.
Show resolved Hide resolved
);
const data = (await res.json()) as AvailableRoutesResponse;

const data = (await res.json()) as AvailableRoutesApiResponse;

// Transform to internal type consistency
return data.map((route) => ({
Expand All @@ -40,3 +35,13 @@ export async function getAvailableRoutes(params?: AvailableRoutesParams) {
outputTokenSymbol: route.destinationTokenSymbol,
}));
}

type AvailableRoutesApiResponse = {
originChainId: number;
originToken: string;
destinationChainId: number;
destinationToken: string;
originTokenSymbol: string;
destinationTokenSymbol: string;
isNative: boolean;
}[];
16 changes: 16 additions & 0 deletions packages/sdk/src/actions/getDepositLogs.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { parseEventLogs, TransactionReceipt } from "viem";
import { spokePoolAbi } from "../constants/abi/SpokePool";

export function getDepositLogs(receipt: TransactionReceipt) {
const parsedLogs = parseEventLogs({
abi: spokePoolAbi,
eventName: "V3FundsDeposited",
logs: receipt.logs,
});

const depositEvent = parsedLogs.find(
(log) => log.args.depositor === receipt.from,
);

return depositEvent;
}
48 changes: 48 additions & 0 deletions packages/sdk/src/actions/getDepositStatus.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { Hash, Log, PublicClient, TransactionReceipt } from "viem";
import { waitForTransactionReceipt } from "viem/actions";
import assert from "assert";
gsteenkamp89 marked this conversation as resolved.
Show resolved Hide resolved
import { getDepositLogs } from "./getDepositLogs";

export type GetDepositStatusParams = {
transactionHash: Hash;
publicClient: PublicClient;
};

export async function getDepositStatus(
gsteenkamp89 marked this conversation as resolved.
Show resolved Hide resolved
params: GetDepositStatusParams,
): Promise<DepositStatus> {
const { transactionHash, publicClient } = params;

const receipt = await waitForTransactionReceipt(publicClient, {
hash: transactionHash,
});

const depositBlock = await publicClient.getBlock({
blockNumber: receipt.blockNumber,
});

const depositLogs = getDepositLogs(receipt);

assert(
depositLogs,
`Unable to get logs from deposit with hash ${transactionHash}`,
);

const depositId = depositLogs.args.depositId;

assert(depositId, "Unable to get deposit Id from transaction logs");

return {
depositTxReceipt: receipt,
parsedDepositLog: depositLogs,
depositTimestamp: depositBlock.timestamp,
depositId,
};
}

export type DepositStatus = {
depositTxReceipt: TransactionReceipt;
parsedDepositLog: Log;
depositTimestamp: bigint;
depositId: number;
};
gsteenkamp89 marked this conversation as resolved.
Show resolved Hide resolved
101 changes: 101 additions & 0 deletions packages/sdk/src/actions/getFillStatus.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
import assert from "assert";
import { buildSearchParams, fetchAcross } from "../utils";
import { DepositStatus } from "./getDepositStatus";
import { Hash, PublicClient } from "viem";
import { QuoteResponse } from "./getQuote";
import { spokePoolAbi } from "../constants/abi/SpokePool";

export type GetFillStatusParams = DepositStatus &
QuoteResponse & {
gsteenkamp89 marked this conversation as resolved.
Show resolved Hide resolved
blockRange: bigint;
gsteenkamp89 marked this conversation as resolved.
Show resolved Hide resolved
destinationChainClient: PublicClient;
indexerUrl: string;
};

export async function getFillStatus(params: GetFillStatusParams) {
gsteenkamp89 marked this conversation as resolved.
Show resolved Hide resolved
const {
depositTxReceipt,
parsedDepositLog,
depositTimestamp,
depositId,
deposit,
blockRange,
destinationChainClient,
indexerUrl,
gsteenkamp89 marked this conversation as resolved.
Show resolved Hide resolved
} = params;

try {
const res = await fetchAcross(
`${indexerUrl}/deposit/status?${buildSearchParams({
depositId,
originChainId: deposit.originChainId,
})}`,
);

if (res.status !== 200) {
throw new Error("Failed to fetch from ");
}

const data = (await res.json()) as {
status: "filled" | "pending";
fillTx: Hash | null;
};
if (data?.status === "filled" && data.fillTx) {
const fillTxReceipt = await destinationChainClient.getTransactionReceipt({
hash: data.fillTx,
});
const fillTxBlock = await destinationChainClient.getBlock({
blockNumber: fillTxReceipt.blockNumber,
});

return {
fillTxHashes: [data.fillTx],
fillTxTimestamp: fillTxBlock.timestamp,
depositData: {
depositTxReceipt,
parsedDepositLog,
depositTimestamp,
depositId,
},
};
}
} catch (e) {
// if fails, attempt to retrieve from publicClient
}

const latestBlock = await destinationChainClient.getBlockNumber();
const filter = await destinationChainClient.createContractEventFilter({
address: deposit.spokePoolAddress,
abi: spokePoolAbi,
eventName: "FilledV3Relay",
args: {
depositId,
},
toBlock: latestBlock,
fromBlock: latestBlock - blockRange, // @todo do we want to implement a blockfinder similar to across frontend?
});

const fillEvents = await destinationChainClient.getFilterLogs({ filter });
assert(fillEvents?.[0], `No v3 fill found for deposit id ${depositId}`);

const fillBlock = await destinationChainClient.getBlock({
blockNumber: fillEvents[0].blockNumber,
});

return {
fillTxHashes: fillEvents.map((e) => e.transactionHash),
fillTxTimestamp: fillBlock.timestamp,
depositData: {
depositTxReceipt,
parsedDepositLog,
depositTimestamp,
depositId,
},
};
}

export type FillStatus = {
fillTxHashes: Hash[];
fillTxTimestamp: bigint;
depositData: DepositStatus;
};
gsteenkamp89 marked this conversation as resolved.
Show resolved Hide resolved
22 changes: 8 additions & 14 deletions packages/sdk/src/actions/getLimits.ts
Original file line number Diff line number Diff line change
@@ -1,27 +1,21 @@
import { Address } from "viem";
import { getClient } from "../client";
import { buildSearchParams, fetchAcross } from "../utils";
import assert from "assert";

export type LimitsParams = {
export type GetLimitsParams = {
destinationChainId: number;
inputToken: Address;
outputToken: Address;
originChainId: number;
apiUrl: string;
};

// might not be necessary if this is part of suggested fees response???
export async function getLimits(params: LimitsParams) {
const client = getClient();
try {
const searchParams = buildSearchParams(params);
const limits = await fetchAcross(`${client.apiUrl}/limits?${searchParams}`);
if (!limits) {
client.log.error("limits failed with params: \n", params);
}
return (await limits.json()) as LimitsResponse;
} catch (error) {
client.log.error(error);
}
export async function getLimits(params: GetLimitsParams) {
const searchParams = buildSearchParams(params);
const limits = await fetchAcross(`${params.apiUrl}/limits?${searchParams}`);
assert(limits, `limits failed with params: \n${JSON.stringify(params)}"`);
return (await limits.json()) as LimitsResponse;
}

export type LimitsResponse = {
Expand Down
Loading
Loading