Skip to content
Draft
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
4 changes: 4 additions & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
@@ -1 +1,5 @@
scripts/build-bigint-buffer.js

# Auto-generated SVM artifacts
src/svm/assets
src/svm/clients
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@ dist
src/utils/abi/contracts/*.json
src/utils/abi/typechain

# Auto-generated SVM artifacts (synced from contracts repo via yarn sync-svm-clients)
src/svm/assets
src/svm/clients/*
!src/svm/clients/index.ts

.ledger
/target
*.tar.gz
Expand Down
29 changes: 23 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@across-protocol/sdk",
"author": "UMA Team",
"version": "4.3.136",
"version": "4.4.0-alpha.5",
"license": "AGPL-3.0",
"homepage": "https://docs.across.to/reference/sdk",
"repository": {
Expand All @@ -22,11 +22,15 @@
"build-bigint-buffer": "node scripts/build-bigint-buffer.js",
"postinstall": "node scripts/build-bigint-buffer.js",
"start": "yarn typechain && nodemon -e ts,tsx,json,js,jsx --watch ./src --ignore ./dist --exec 'yarn dev'",
"build": "yarn run clean && yarn typechain && yarn dev",
"build": "yarn run clean && yarn typechain && yarn generate-svm-artifacts && yarn dev",
"generate-svm-artifacts": "bash scripts/svm/generateSvmAssets.sh && yarn generate-svm-clients",
"generate-svm-clients": "ts-node scripts/svm/generateSvmClients.ts && ts-node scripts/svm/renameClientsImports.ts",
"dev": "concurrently --kill-others-on-fail --names 'cjs,esm,types' --prefix-colors 'blue,magenta,green' 'yarn run build:cjs' 'yarn run build:esm' 'yarn run build:types'",
"build:cjs": "tsc --project tsconfig.build.json --module commonjs --outDir ./dist/cjs --removeComments --verbatimModuleSyntax false && echo > ./dist/cjs/package.json '{\"type\":\"commonjs\"}'",
"build:esm": "tsc --project tsconfig.build.json --module es2015 --outDir ./dist/esm && echo > ./dist/esm/package.json '{\"type\":\"module\",\"sideEffects\":false}'",
"build:cjs": "tsc --project tsconfig.build.json --module commonjs --outDir ./dist/cjs --removeComments --verbatimModuleSyntax false && echo > ./dist/cjs/package.json '{\"type\":\"commonjs\"}' && yarn export-svm-idl:cjs",
"build:esm": "tsc --project tsconfig.build.json --module es2015 --outDir ./dist/esm && echo > ./dist/esm/package.json '{\"type\":\"module\",\"sideEffects\":false}' && yarn export-svm-idl:esm",
"build:types": "tsc --project tsconfig.build.json --module esnext --declarationDir ./dist/types --emitDeclarationOnly --declaration --declarationMap",
"export-svm-idl:cjs": "cp src/svm/assets/idl/*.json dist/cjs/src/svm/assets/idl/",
"export-svm-idl:esm": "cp src/svm/assets/idl/*.json dist/esm/src/svm/assets/idl/",
"test": "hardhat test",
"test:watch": "hardhat watch test",
"test:run:arweave": "npx -y arlocal",
Expand Down Expand Up @@ -59,13 +63,15 @@
}
],
"devDependencies": {
"@codama/nodes-from-anchor": "^1.2.2",
"@codama/renderers-js": "^1.3.0",
"codama": "^1.3.0",
"@defi-wonderland/smock": "^2.4.0",
"@nomicfoundation/hardhat-chai-matchers": "^1.0.6",
"@nomiclabs/hardhat-ethers": "^2.2.1",
"@nomiclabs/hardhat-etherscan": "^3.1.7",
"@openzeppelin/hardhat-upgrades": "^1.28.0",
"@size-limit/preset-small-lib": "^7.0.8",
"@solana/web3.js": "^1.31.0",
"@typechain/ethers-v5": "^11.1.1",
"@typechain/hardhat": "^6.1.6",
"@types/async": "^3.2.24",
Expand Down Expand Up @@ -113,7 +119,8 @@
"dependencies": {
"@across-protocol/constants": "^3.1.100",
"@across-protocol/contracts": "5.0.4",
"@coral-xyz/anchor": "^0.30.1",
"@coral-xyz/anchor": "^0.31.1",
"@coral-xyz/borsh": "^0.31.1",
"@eth-optimism/sdk": "^3.3.1",
"@ethersproject/bignumber": "^5.7.0",
"@nktkas/hyperliquid": "^0.25.9",
Expand All @@ -123,9 +130,14 @@
"@solana-program/token": "^0.9.0",
"@solana-program/token-2022": "^0.6.1",
"@solana/kit": "^5.4.0",
"@solana/spl-token": "^0.4.14",
"@solana/sysvars": "^5.4.0",
"@solana/web3.js": "^1.98.2",
"@solana-program/address-lookup-table": "^0.10.0",
"@uma/contracts-node": "^0.4.0",
"arweave": "^1.14.4",
"borsh": "0.7.0",
"buffer-layout": "^1.2.2",
"async": "^3.2.5",
"axios": "^0.27.2",
"bs58": "^6.0.0",
Expand Down Expand Up @@ -168,6 +180,11 @@
"import": "./dist/esm/typechain.js",
"types": "./dist/types/typechain.d.ts"
},
"./svm": {
"require": "./dist/cjs/src/svm/index.js",
"import": "./dist/esm/src/svm/index.js",
"types": "./dist/types/src/svm/index.d.ts"
},
"./src/utils/abi/typechain": {
"require": "./dist/cjs/src/utils/abi/typechain/index.js",
"import": "./dist/esm/src/utils/abi/typechain/index.js",
Expand Down
106 changes: 106 additions & 0 deletions scripts/svm/generateSvmAssets.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
#!/bin/bash
# Generates SVM assets (IDL index + Anchor type re-exports) from @across-protocol/contracts.
# The SDK generates its own artifacts from the installed contracts package.

set -euo pipefail

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
SDK_ROOT="$(dirname "$(dirname "$SCRIPT_DIR")")"
CONTRACTS_PKG="$SDK_ROOT/node_modules/@across-protocol/contracts"

SVM_ASSETS="$SDK_ROOT/src/svm/assets"
SVM_IDL="$SVM_ASSETS/idl"
IDL_OUTPUT_FILE="$SVM_IDL/index.ts"
TYPES_OUTPUT_FILE="$SVM_ASSETS/index.ts"

# Source IDL and types from installed contracts package
SOURCE_IDL="$CONTRACTS_PKG/dist/src/svm/assets/idl"
# Anchor types live in dist/src/svm/assets/ (v5+) or dist/target/types/ (v4)
SOURCE_TYPES="$CONTRACTS_PKG/dist/src/svm/assets"
if [ ! -d "$SOURCE_TYPES" ] || [ "$(ls "$SOURCE_TYPES"/*.d.ts 2>/dev/null | grep -v index | wc -l)" -eq 0 ]; then
SOURCE_TYPES="$CONTRACTS_PKG/dist/target/types"
fi

if [ ! -d "$SOURCE_IDL" ]; then
echo "Error: IDL files not found at $SOURCE_IDL"
echo "Make sure @across-protocol/contracts is installed."
exit 1
fi

# Ensure destination directories exist
mkdir -p "$SVM_IDL"
mkdir -p "$SVM_ASSETS"

# --- Copy IDL JSON files ---
echo "Copying IDL JSON files from contracts package..."
cp "$SOURCE_IDL"/*.json "$SVM_IDL/"

# --- Generate IDL index.ts ---
echo "Generating IDL index.ts..."
> "$IDL_OUTPUT_FILE"

{
echo "// This file has been autogenerated. Do not edit manually."
echo "// Generated by scripts/svm/generateSvmAssets.sh"
echo
} >> "$IDL_OUTPUT_FILE"

IMPORTS=""
EXPORTS=""

for file in "$SVM_IDL"/*.json; do
filename=$(basename -- "$file")
name="${filename%.json}"
camelCaseName=$(echo "$name" | awk -F'_' '{
for (i=1; i<=NF; i++) {
printf toupper(substr($i,1,1)) tolower(substr($i,2));
}
}')
IMPORTS="${IMPORTS}const ${camelCaseName}Idl = require(\"./${filename}\");\n"
EXPORTS="${EXPORTS} ${camelCaseName}Idl,\n"
done

printf "$IMPORTS" >> "$IDL_OUTPUT_FILE"

{
echo "export {"
printf "$EXPORTS" | sed '$ s/,$//'
echo "};"
} >> "$IDL_OUTPUT_FILE"

echo "IDL index.ts generated at $IDL_OUTPUT_FILE"

# --- Generate assets index.ts (Anchor type re-exports) ---
echo "Generating assets index.ts..."
> "$TYPES_OUTPUT_FILE"

{
echo "// This file has been autogenerated. Do not edit manually."
echo "// Generated by scripts/svm/generateSvmAssets.sh"
echo
echo "export * from \"./idl\";"
} >> "$TYPES_OUTPUT_FILE"

# Determine the import path prefix based on which source directory we're using
if echo "$SOURCE_TYPES" | grep -q "dist/src/svm/assets"; then
IMPORT_PREFIX="@across-protocol/contracts/dist/src/svm/assets"
else
IMPORT_PREFIX="@across-protocol/contracts/dist/target/types"
fi

# Re-export Anchor types from the contracts package
for file in "$SOURCE_TYPES"/*.d.ts; do
filename=$(basename -- "$file")
[ "$filename" = "index.d.ts" ] && continue
name="${filename%.d.ts}"
camelCaseName=$(echo "$name" | awk -F'_' '{
for (i=1; i<=NF; i++) {
printf toupper(substr($i,1,1)) tolower(substr($i,2));
}
}')
newName="${camelCaseName}Anchor"
echo "export {${camelCaseName} as ${newName}} from \"${IMPORT_PREFIX}/${name}\";" >> "$TYPES_OUTPUT_FILE"
done

echo "Assets index.ts generated at $TYPES_OUTPUT_FILE"
echo "Done generating SVM assets."
47 changes: 47 additions & 0 deletions scripts/svm/generateSvmClients.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/**
* Generates Codama TypeScript clients from IDL files.
* Reads IDL assets from the locally generated src/svm/assets/idl/ directory
* (populated by generateSvmAssets.sh).
*
* This is the SDK's own generation script, equivalent to the one in the contracts repo.
*/
import { createFromRoot } from "codama";
import { rootNodeFromAnchor, AnchorIdl } from "@codama/nodes-from-anchor";
import { renderVisitor as renderJavaScriptVisitor } from "@codama/renderers-js";
import path from "path";

// Read IDL files directly from the generated assets
const idlPath = path.join(__dirname, "..", "..", "src", "svm", "assets", "idl");
const clientsPath = path.join(__dirname, "..", "..", "src", "svm", "clients");

const SvmSpokeIdl = require(path.join(idlPath, "svm_spoke.json"));
const MulticallHandlerIdl = require(path.join(idlPath, "multicall_handler.json"));
const MessageTransmitterIdl = require(path.join(idlPath, "message_transmitter.json"));
const TokenMessengerMinterIdl = require(path.join(idlPath, "token_messenger_minter.json"));
const MessageTransmitterV2Idl = require(path.join(idlPath, "message_transmitter_v2.json"));
const TokenMessengerMinterV2Idl = require(path.join(idlPath, "token_messenger_minter_v2.json"));
const SponsoredCctpSrcPeripheryIdl = require(path.join(idlPath, "sponsored_cctp_src_periphery.json"));

// Generate clients for each program
let codama = createFromRoot(rootNodeFromAnchor(SvmSpokeIdl as AnchorIdl));
codama.accept(renderJavaScriptVisitor(path.join(clientsPath, "SvmSpoke")));

codama = createFromRoot(rootNodeFromAnchor(MulticallHandlerIdl as AnchorIdl));
codama.accept(renderJavaScriptVisitor(path.join(clientsPath, "MulticallHandler")));

codama = createFromRoot(rootNodeFromAnchor(MessageTransmitterIdl as AnchorIdl));
codama.accept(renderJavaScriptVisitor(path.join(clientsPath, "MessageTransmitter")));

codama = createFromRoot(rootNodeFromAnchor(TokenMessengerMinterIdl as AnchorIdl));
codama.accept(renderJavaScriptVisitor(path.join(clientsPath, "TokenMessengerMinter")));

codama = createFromRoot(rootNodeFromAnchor(MessageTransmitterV2Idl as AnchorIdl));
codama.accept(renderJavaScriptVisitor(path.join(clientsPath, "MessageTransmitterV2")));

codama = createFromRoot(rootNodeFromAnchor(TokenMessengerMinterV2Idl as AnchorIdl));
codama.accept(renderJavaScriptVisitor(path.join(clientsPath, "TokenMessengerMinterV2")));

codama = createFromRoot(rootNodeFromAnchor(SponsoredCctpSrcPeripheryIdl as AnchorIdl));
codama.accept(renderJavaScriptVisitor(path.join(clientsPath, "SponsoredCctpSrcPeriphery")));

console.log("Codama clients generated at", clientsPath);
27 changes: 27 additions & 0 deletions scripts/svm/renameClientsImports.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/**
* Post-processes generated Codama clients to replace @solana/web3.js imports with @solana/kit.
* This is needed because Codama generates imports for @solana/web3.js by default.
*/
const fs = require("fs");
const path = require("path");

const clientsPath = path.join(__dirname, "..", "..", "src", "svm", "clients");

function replaceInFiles(dir: string): void {
const files = fs.readdirSync(dir);
files.forEach((file: string) => {
const filePath = path.join(dir, file);
const stat = fs.statSync(filePath);

if (stat.isDirectory()) {
replaceInFiles(filePath);
} else if (file.endsWith(".ts")) {
const fileContent = fs.readFileSync(filePath, "utf8");
const updatedContent = fileContent.replace("@solana/web3.js", "@solana/kit");
fs.writeFileSync(filePath, updatedContent);
}
});
}

replaceInFiles(clientsPath);
console.log("Client imports renamed (@solana/web3.js -> @solana/kit)");
11 changes: 5 additions & 6 deletions src/arch/svm/SpokeUtils.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { MessageTransmitterClient, SvmSpokeClient, TokenMessengerMinterClient } from "@across-protocol/contracts";
import { decodeFillStatusAccount, fetchState } from "@across-protocol/contracts/dist/src/svm/clients/SvmSpoke";
import { decodeMessageHeader } from "@across-protocol/contracts/dist/src/svm/web3-v1";
import { MessageTransmitterClient, SvmSpokeClient, TokenMessengerMinterClient } from "../../svm";
import { decodeMessageHeader } from "../../svm/web3-v1/cctpHelpers";
import { SYSTEM_PROGRAM_ADDRESS } from "@solana-program/system";
import {
ASSOCIATED_TOKEN_PROGRAM_ADDRESS,
Expand Down Expand Up @@ -210,7 +209,7 @@ async function _callGetTimestampForSlotWithRetry(
* @returns fill deadline buffer
*/
export async function getFillDeadline(provider: SVMProvider, statePda: Address): Promise<number> {
const state = await fetchState(provider, statePda);
const state = await SvmSpokeClient.fetchState(provider, statePda);
return state.data.fillDeadlineBuffer;
}

Expand Down Expand Up @@ -341,7 +340,7 @@ export async function relayFillStatus(

// If the PDA exists, return the stored fill status
if (fillStatusAccount.exists) {
const decodedAccountData = decodeFillStatusAccount(fillStatusAccount);
const decodedAccountData = SvmSpokeClient.decodeFillStatusAccount(fillStatusAccount);
return decodedAccountData.data.status;
}
// If the PDA doesn't exist and the deadline hasn't passed yet, the deposit must be unfilled,
Expand Down Expand Up @@ -1068,7 +1067,7 @@ async function fetchBatchFillStatusFromPdaAccounts(
const fillStatuses = pdaAccounts.flat().map((account, index) => {
// If the PDA exists, we can fetch the status directly.
if (account.exists) {
const decodedAccount = decodeFillStatusAccount(account);
const decodedAccount = SvmSpokeClient.decodeFillStatusAccount(account);
return decodedAccount.data.status;
}

Expand Down
5 changes: 3 additions & 2 deletions src/arch/svm/eventsClient.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Idl } from "@coral-xyz/anchor";
import { getDeployedAddress, SvmSpokeIdl } from "@across-protocol/contracts";
import { getSolanaChainId } from "@across-protocol/contracts/dist/src/svm/web3-v1";
import { getDeployedAddress } from "@across-protocol/contracts";
import { SvmSpokeIdl } from "../../svm";
import { getSolanaChainId } from "../../svm/web3-v1/helpers";
import {
address,
Address,
Expand Down
2 changes: 1 addition & 1 deletion src/arch/svm/types.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { SvmSpokeClient } from "@across-protocol/contracts";
import { SvmSpokeClient } from "../../svm";
import {
Address,
Rpc,
Expand Down
2 changes: 1 addition & 1 deletion src/arch/svm/utils.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { MessageTransmitterClient, SvmSpokeClient } from "@across-protocol/contracts";
import { MessageTransmitterClient, SvmSpokeClient } from "../../svm";
import { SpokePool__factory } from "../../typechain";
import { BN, BorshEventCoder, Idl } from "@coral-xyz/anchor";
import {
Expand Down
2 changes: 1 addition & 1 deletion src/clients/mocks/MockSvmCpiEventsClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { hexlify, arrayify, hexZeroPad } from "ethers/lib/utils";
import { random } from "lodash";
import { Address, UnixTimestamp, signature } from "@solana/kit";
import { Idl } from "@coral-xyz/anchor";
import { SvmSpokeClient } from "@across-protocol/contracts";
import { SvmSpokeClient } from "../../svm";
import { CHAIN_IDs } from "@across-protocol/constants";

import { MockSolanaRpcFactory } from "../../providers/mocks";
Expand Down
2 changes: 1 addition & 1 deletion src/clients/mocks/MockSvmSpokePoolClient.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import winston from "winston";
import { SvmSpokeClient } from "@across-protocol/contracts";
import { SvmSpokeClient } from "../../svm";
import { Address } from "@solana/kit";
import { DepositWithBlock, RelayerRefundExecution, SortableEvent, SlowFillLeaf, Log } from "../../interfaces";
import {
Expand Down
17 changes: 17 additions & 0 deletions src/svm/clients/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import * as MulticallHandlerClient from "./MulticallHandler";
import * as SvmSpokeClient from "./SvmSpoke";
import * as MessageTransmitterClient from "./MessageTransmitter";
import * as TokenMessengerMinterClient from "./TokenMessengerMinter";
import * as MessageTransmitterV2Client from "./MessageTransmitterV2";
import * as TokenMessengerMinterV2Client from "./TokenMessengerMinterV2";
import * as SponsoredCctpSrcPeripheryClient from "./SponsoredCctpSrcPeriphery";

export {
MulticallHandlerClient,
SvmSpokeClient,
MessageTransmitterClient,
TokenMessengerMinterClient,
MessageTransmitterV2Client,
TokenMessengerMinterV2Client,
SponsoredCctpSrcPeripheryClient,
};
Loading
Loading