Skip to content

Commit

Permalink
feat: update scripts (#776)
Browse files Browse the repository at this point in the history
  • Loading branch information
chrismaree authored Dec 6, 2024
1 parent 5908cfd commit e23fab1
Show file tree
Hide file tree
Showing 12 changed files with 119 additions and 31 deletions.
2 changes: 2 additions & 0 deletions Anchor.toml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ bridgeLiabilityToHubPool = "NODE_NO_WARNINGS=1 yarn run ts-node ./scripts/svm/br
remoteHubPoolPauseDeposits = "NODE_NO_WARNINGS=1 yarn run ts-node ./scripts/svm/remoteHubPoolPauseDeposits.ts"
generateExternalTypes = "NODE_NO_WARNINGS=1 yarn run ts-node ./scripts/svm/generateExternalTypes.ts"
fakeFillWithRandomDistribution = "NODE_NO_WARNINGS=1 yarn run ts-node ./scripts/svm/fakeFillWithRandomDistribution.ts"
addressToPublicKey = "NODE_NO_WARNINGS=1 yarn run ts-node ./scripts/svm/addressToPublicKey.ts"
publicKeyToAddress = "NODE_NO_WARNINGS=1 yarn run ts-node ./scripts/svm/publicKeyToAddress.ts"

[test.validator]
url = "https://api.mainnet-beta.solana.com"
Expand Down
18 changes: 18 additions & 0 deletions scripts/svm/addressToPublicKey.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { evmAddressToPublicKey } from "../../src/SvmUtils";
import yargs from "yargs";
import { hideBin } from "yargs/helpers";
const argv = yargs(hideBin(process.argv)).option("address", {
type: "string",
demandOption: true,
describe: "Ethereum address to convert",
}).argv;

async function logPublicKey(): Promise<void> {
const address = (await argv).address;

const publicKey = evmAddressToPublicKey(address);

console.log("Ethereum Address:", address);
console.log("Associated Public Key:", publicKey.toString());
}
logPublicKey();
8 changes: 7 additions & 1 deletion scripts/svm/enableRoute.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ anchor.setProvider(provider);
const idl = require("../../target/idl/svm_spoke.json");
const program = new Program<SvmSpoke>(idl, provider);
const programId = program.programId;
console.log("SVM-Spoke Program ID:", programId.toString());

// Parse arguments
const argv = yargs(hideBin(process.argv))
Expand All @@ -37,7 +38,12 @@ async function enableRoute(): Promise<void> {

// Define the route account PDA
const [routePda] = PublicKey.findProgramAddressSync(
[Buffer.from("route"), originToken.toBytes(), statePda.toBytes(), chainId.toArrayLike(Buffer, "le", 8)],
[
Buffer.from("route"),
originToken.toBytes(),
seed.toArrayLike(Buffer, "le", 8),
chainId.toArrayLike(Buffer, "le", 8),
],
programId
);

Expand Down
19 changes: 19 additions & 0 deletions scripts/svm/publicKeyToAddress.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { publicKeyToEvmAddress } from "../../src/SvmUtils";
import yargs from "yargs";
import { hideBin } from "yargs/helpers";

const argv = yargs(hideBin(process.argv)).option("publicKey", {
type: "string",
demandOption: true,
describe: "Public key to convert",
}).argv;

async function logEvmAddress(): Promise<void> {
const publicKey = (await argv).publicKey;
const evmAddress = publicKeyToEvmAddress(publicKey);

console.log("Public Key:", publicKey);
console.log("Associated Ethereum Address:", evmAddress);
}

logEvmAddress();
1 change: 1 addition & 0 deletions scripts/svm/queryDeposits.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ anchor.setProvider(provider);
const idl = require("../../target/idl/svm_spoke.json");
const program = new Program<SvmSpoke>(idl, provider);
const programId = program.programId;
console.log("SVM-Spoke Program ID:", programId.toString());

// Parse arguments
const argvPromise = yargs(hideBin(process.argv)).option("seed", {
Expand Down
26 changes: 12 additions & 14 deletions scripts/svm/queryFills.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ import { PublicKey } from "@solana/web3.js";
import { SvmSpoke } from "../../target/types/svm_spoke";
import yargs from "yargs";
import { hideBin } from "yargs/helpers";
import { readProgramEvents } from "../../src/SvmUtils";
import { readProgramEvents, strPublicKey } from "../../src/SvmUtils";
import { u8Array32ToInt } from "../../test/svm/utils";

// Set up the provider
const provider = AnchorProvider.env();
Expand Down Expand Up @@ -46,30 +47,27 @@ async function queryFills(): Promise<void> {
console.log("No fill events found for the given seed.");
return;
}

console.log("Fill events fetched successfully:");
fillEvents.forEach((event, index) => {
console.log(`Fill Event ${index + 1}:`);
console.table([
{ Property: "inputToken", Value: new PublicKey(event.data.inputToken).toString() },
{ Property: "outputToken", Value: new PublicKey(event.data.outputToken).toString() },
{ Property: "inputToken", Value: strPublicKey(event.data.inputToken) },
{ Property: "outputToken", Value: strPublicKey(event.data.outputToken) },
{ Property: "inputAmount", Value: event.data.inputAmount.toString() },
{ Property: "outputAmount", Value: event.data.outputAmount.toString() },
{ Property: "repaymentChainId", Value: event.data.repaymentChainId.toString() },
{ Property: "originChainId", Value: event.data.originChainId.toString() },
{ Property: "depositId", Value: event.data.depositId.toString() },
{ Property: "depositIdNum", Value: u8Array32ToInt(event.data.depositId).toString() },
{ Property: "fillDeadline", Value: event.data.fillDeadline.toString() },
{ Property: "exclusivityDeadline", Value: event.data.exclusivityDeadline.toString() },
{ Property: "exclusiveRelayer", Value: new PublicKey(event.data.exclusiveRelayer).toString() },
{ Property: "relayer", Value: new PublicKey(event.data.relayer).toString() },
{ Property: "depositor", Value: new PublicKey(event.data.depositor).toString() },
{ Property: "recipient", Value: new PublicKey(event.data.recipient).toString() },
{ Property: "message", Value: event.data.message.toString() },
{
Property: "updatedRecipient",
Value: new PublicKey(event.data.relayExecutionInfo.updatedRecipient).toString(),
},
{ Property: "updatedMessage", Value: event.data.relayExecutionInfo.updatedMessage.toString() },
{ Property: "exclusiveRelayer", Value: strPublicKey(event.data.exclusiveRelayer) },
{ Property: "relayer", Value: strPublicKey(event.data.relayer) },
{ Property: "depositor", Value: strPublicKey(event.data.depositor) },
{ Property: "recipient", Value: strPublicKey(event.data.recipient) },
{ Property: "messageHash", Value: event.data.messageHash.toString() },
{ Property: "updatedRecipient", Value: strPublicKey(event.data.relayExecutionInfo.updatedRecipient) },
{ Property: "updatedMessageHash", Value: event.data.relayExecutionInfo.updatedMessageHash.toString() },
{ Property: "updatedOutputAmount", Value: event.data.relayExecutionInfo.updatedOutputAmount.toString() },
{ Property: "fillType", Value: event.data.relayExecutionInfo.fillType },
]);
Expand Down
8 changes: 7 additions & 1 deletion scripts/svm/queryRoute.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ anchor.setProvider(provider);
const idl = require("../../target/idl/svm_spoke.json");
const program = new Program<SvmSpoke>(idl, provider);
const programId = program.programId;
console.log("SVM-Spoke Program ID:", programId.toString());

// Parse arguments
const argv = yargs(hideBin(process.argv))
Expand All @@ -40,7 +41,12 @@ async function queryRoute(): Promise<void> {

// Define the route account PDA
const [routePda] = PublicKey.findProgramAddressSync(
[Buffer.from("route"), Buffer.from(originToken), statePda.toBytes(), chainId.toArrayLike(Buffer, "le", 8)],
[
Buffer.from("route"),
Buffer.from(originToken),
seed.toArrayLike(Buffer, "le", 8),
chainId.toArrayLike(Buffer, "le", 8),
],
programId
);

Expand Down
1 change: 1 addition & 0 deletions scripts/svm/queryState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ anchor.setProvider(provider);
const idl = require("../../target/idl/svm_spoke.json");
const program = new Program<SvmSpoke>(idl, provider);
const programId = program.programId;
console.log("SVM-Spoke Program ID:", programId.toString());

// Parse arguments
const argv = yargs(hideBin(process.argv)).option("seed", {
Expand Down
8 changes: 7 additions & 1 deletion scripts/svm/simpleDeposit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ anchor.setProvider(provider);
const idl = require("../../target/idl/svm_spoke.json");
const program = new Program<SvmSpoke>(idl, provider);
const programId = program.programId;
console.log("SVM-Spoke Program ID:", programId.toString());

// Parse arguments
const argv = yargs(hideBin(process.argv))
Expand Down Expand Up @@ -54,7 +55,12 @@ async function depositV3(): Promise<void> {

// Define the route account PDA
const [routePda] = PublicKey.findProgramAddressSync(
[Buffer.from("route"), inputToken.toBytes(), statePda.toBytes(), destinationChainId.toArrayLike(Buffer, "le", 8)],
[
Buffer.from("route"),
inputToken.toBytes(),
seed.toArrayLike(Buffer, "le", 8),
destinationChainId.toArrayLike(Buffer, "le", 8),
],
programId
);

Expand Down
9 changes: 5 additions & 4 deletions scripts/svm/simpleFill.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { SvmSpoke } from "../../target/types/svm_spoke";
import yargs from "yargs";
import { hideBin } from "yargs/helpers";
import { calculateRelayHashUint8Array } from "../../src/SvmUtils";
import { intToU8Array32 } from "../../test/svm/utils";

// Set up the provider
const provider = AnchorProvider.env();
Expand All @@ -35,7 +36,7 @@ const argv = yargs(hideBin(process.argv))
.option("inputAmount", { type: "number", demandOption: true, describe: "Input amount" })
.option("outputAmount", { type: "number", demandOption: true, describe: "Output amount" })
.option("originChainId", { type: "string", demandOption: true, describe: "Origin chain ID" })
.option("depositId", { type: "array", demandOption: true, describe: "Deposit ID" })
.option("depositId", { type: "string", demandOption: true, describe: "Deposit ID" })
.option("fillDeadline", { type: "number", demandOption: false, describe: "Fill deadline" })
.option("exclusivityDeadline", { type: "number", demandOption: false, describe: "Exclusivity deadline" }).argv;

Expand All @@ -49,7 +50,7 @@ async function fillV3Relay(): Promise<void> {
const inputAmount = new BN(resolvedArgv.inputAmount);
const outputAmount = new BN(resolvedArgv.outputAmount);
const originChainId = new BN(resolvedArgv.originChainId);
const depositId = resolvedArgv.depositId;
const depositId = intToU8Array32(new BN(resolvedArgv.depositId));
const fillDeadline = resolvedArgv.fillDeadline || Math.floor(Date.now() / 1000) + 60; // Current time + 1 minute
const exclusivityDeadline = resolvedArgv.exclusivityDeadline || Math.floor(Date.now() / 1000) + 30; // Current time + 30 seconds
const message = Buffer.from("");
Expand All @@ -64,7 +65,7 @@ async function fillV3Relay(): Promise<void> {
inputAmount,
outputAmount,
originChainId,
depositId: depositId.map((id) => Number(id)),
depositId,
fillDeadline,
exclusivityDeadline,
message,
Expand Down Expand Up @@ -154,7 +155,7 @@ async function fillV3Relay(): Promise<void> {
state: statePda,
signer: signer.publicKey,
instructionParams: program.programId,
mintAccount: outputToken,
mint: outputToken,
relayerTokenAccount: relayerTokenAccount,
recipientTokenAccount: recipientTokenAccount,
fillStatus: fillStatusPda,
Expand Down
15 changes: 15 additions & 0 deletions src/SvmUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,17 @@ export const evmAddressToPublicKey = (address: string): PublicKey => {
return new PublicKey(ethers.utils.arrayify(bytes32Address));
};

export const publicKeyToEvmAddress = (publicKey: PublicKey | string): string => {
// Convert the input to a PublicKey if it's a string
const pubKeyBuffer = typeof publicKey === "string" ? new PublicKey(publicKey).toBuffer() : publicKey.toBuffer();

// Extract the last 20 bytes to get the Ethereum address
const addressBuffer = pubKeyBuffer.slice(-20);

// Convert the buffer to a hex string and prepend '0x'
return `0x${addressBuffer.toString("hex")}`;
};

// TODO: we are inconsistant with where we are placing some utils. we have some stuff here, some stuff that we might
// want to re-use within the test directory. more over, when moving things into the canonical across repo, we should
// re-use the test utils there.
Expand Down Expand Up @@ -583,3 +594,7 @@ export function hashNonEmptyMessage(message: Buffer) {
// else return zeroed bytes32
return new Uint8Array(32);
}

export function strPublicKey(publicKey: PublicKey): string {
return new PublicKey(publicKey).toString();
}
35 changes: 25 additions & 10 deletions test/svm/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -431,26 +431,41 @@ export async function loadExecuteV3SlowRelayLeafParams(
return loadInstructions;
}

export function intToU8Array32(num: number): number[] {
if (!Number.isInteger(num) || num < 0) {
throw new Error("Input must be a non-negative integer");
export function intToU8Array32(num: number | BN): number[] {
let bigIntValue: bigint;

if (typeof num === "number") {
if (!Number.isInteger(num) || num < 0) {
throw new Error("Input must be a non-negative integer");
}
bigIntValue = BigInt(num);
} else if (BN.isBN(num)) {
if (num.isNeg()) {
throw new Error("Input must be a non-negative BN");
}
bigIntValue = BigInt(num.toString());
} else {
throw new Error("Input must be a non-negative integer or BN");
}

const u8Array = new Array(32).fill(0);
let i = 0;
while (num > 0 && i < 32) {
u8Array[i++] = num & 0xff; // Get least significant byte
num >>= 8; // Shift right by 8 bits
while (bigIntValue > 0 && i < 32) {
u8Array[i++] = Number(bigIntValue & 0xffn); // Get least significant byte
bigIntValue >>= 8n; // Shift right by 8 bits
}

return u8Array;
}

export function u8Array32ToInt(u8Array: Uint8Array): bigint {
if (!(u8Array instanceof Uint8Array) || u8Array.length !== 32) {
throw new Error("Input must be a Uint8Array of length 32");
export function u8Array32ToInt(u8Array: Uint8Array | number[]): bigint {
const isValidArray = (arr: any): arr is number[] => Array.isArray(arr) && arr.every(Number.isInteger);

if ((u8Array instanceof Uint8Array || isValidArray(u8Array)) && u8Array.length === 32) {
return Array.from(u8Array).reduce<bigint>((num, byte, i) => num | (BigInt(byte) << BigInt(i * 8)), 0n);
}
return u8Array.reduce((num, byte, i) => num | (BigInt(byte) << BigInt(i * 8)), 0n);

throw new Error("Input must be a Uint8Array or an array of 32 numbers.");
}

// Encodes empty list of multicall handler instructions to be used as a test message field for fills.
Expand Down

0 comments on commit e23fab1

Please sign in to comment.