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

solana localnet #62

Draft
wants to merge 16 commits into
base: localnet-authenticated-call
Choose a base branch
from
Draft
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,5 @@ tsconfig.tsbuildinfo
.wallet.json

localnet.pid

test-ledger
18 changes: 18 additions & 0 deletions Anchor.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
[toolchain]

[features]
resolution = true
skip-lint = false

[programs.localnet]
protocol_contracts_solana = "94U5AHQMKkV5txNJ17QPXWoh474PheGou6cNP2FEuL1d"

[registry]
url = "https://api.apr.dev"

[provider]
cluster = "Localnet"
wallet = "~/.config/solana/id.json"

[scripts]
test = "yarn run ts-mocha -p ./tsconfig.json -t 1000000 tests/**/*.ts"
8 changes: 7 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
"license": "MIT",
"packageManager": "[email protected]+sha1.1959a18351b811cdeedbd484a8f86c3cc3bbaf72",
"devDependencies": {
"@types/elliptic": "^6.4.18",
"@types/wait-on": "^5.3.4",
"@typescript-eslint/eslint-plugin": "^8.0.1",
"@typescript-eslint/parser": "^8.0.1",
Expand All @@ -33,14 +34,19 @@
"typescript": "^5.5.4"
},
"dependencies": {
"@coral-xyz/anchor": "^0.30.1",
"@inquirer/prompts": "^5.5.0",
"@solana/web3.js": "^1.95.4",
"@uniswap/v2-core": "^1.0.1",
"@uniswap/v2-periphery": "^1.1.0-beta.0",
"@zetachain/protocol-contracts": "11.0.0-rc3",
"@zetachain/protocol-contracts-solana": "^2.0.0-rc1",
"ansis": "^3.3.2",
"bs58": "^6.0.0",
"concurrently": "^8.2.2",
"elliptic": "6.5.7",
"ethers": "^6.13.2",
"hardhat": "^2.22.8",
"wait-on": "^7.2.0"
}
}
}
113 changes: 113 additions & 0 deletions packages/localnet/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ import { handleOnZEVMWithdrawn } from "./handleOnZEVMWithdrawn";
import { createToken } from "./createToken";
import { handleOnZEVMWithdrawnAndCalled } from "./handleOnZEVMWithdrawnAndCalled";
import { handleOnEVMDepositedAndCalled } from "./handleOnEVMDepositedAndCalled";
import { setupSolana } from "./setupSolana";
import * as anchor from "@coral-xyz/anchor";
import * as borsh from "borsh";

const FUNGIBLE_MODULE_ADDRESS = "0x735b14BB79463307AAcBED86DAf3322B1e6226aB";

Expand Down Expand Up @@ -246,6 +249,97 @@ const deployProtocolContracts = async (
uniswapRouterInstance,
};
};
async function monitorOnlyNewTransactions(program: any, connection: any) {
console.log(
`Monitoring new transactions for program: ${program.programId.toBase58()}`
);

let lastSignature: string | undefined = undefined;

setInterval(async () => {
let signatures;
try {
signatures = await connection.getSignaturesForAddress(
program.programId,
{ limit: 10 },
"confirmed"
);

if (signatures.length === 0) return;

const newSignatures = [];

for (const signatureInfo of signatures) {
if (signatureInfo.signature === lastSignature) {
break;
} else {
newSignatures.push(signatureInfo);
}
}

if (newSignatures.length === 0) return;

for (const signatureInfo of newSignatures.reverse()) {
try {
const transaction = await connection.getTransaction(
signatureInfo.signature,
{ commitment: "confirmed" }
);

if (transaction) {
console.log("New Transaction Details:", transaction);

for (const instruction of transaction.transaction.message
.instructions) {
const programIdIndex =
instruction.programIdIndex || instruction.programId;
const programIdFromInstruction =
transaction.transaction.message.accountKeys[programIdIndex];

if (
programIdFromInstruction &&
programIdFromInstruction.equals(program.programId)
) {
console.log("Instruction for program detected:", instruction);
const DepositInstructionSchema = {
struct: {
discriminator: { array: { type: "u8", length: 8 } }, // 8-byte discriminator
amount: "u64", // Amount as uint64
receiver: { array: { type: "u8", length: 20 } }, // Receiver as 20-byte array
},
};

const rawData = Buffer.from(instruction.data, "base64");
const decoded = borsh.deserialize(
DepositInstructionSchema,
rawData
);

const decodedInstruction =
program.coder.instruction.decode(rawData);
console.log("Decoded Instruction:", decoded);
}
}
}
} catch (transactionError) {
console.error(
`Error processing transaction ${signatureInfo.signature}:`,
transactionError
);
// Continue to the next transaction even if an error occurs
continue;
}
}
} catch (error) {
console.error("Error monitoring new transactions:", error);
} finally {
// Update lastSignature even if an error occurs
if (signatures && signatures.length > 0) {
lastSignature = signatures[0].signature;
}
}
}, 1000);
}

export const initLocalnet = async ({
port,
Expand All @@ -254,6 +348,25 @@ export const initLocalnet = async ({
port: number;
exitOnError: boolean;
}) => {
const { gatewayProgram, address } = await setupSolana();

const connection = gatewayProgram.provider.connection;
await gatewayProgram.methods
.deposit(new anchor.BN(1_000_000_000), Array.from(address))
.accounts({})
.rpc();

await new Promise((r) => setTimeout(r, 7000));

monitorOnlyNewTransactions(gatewayProgram, connection);

await new Promise((r) => setTimeout(r, 7000));

await gatewayProgram.methods
.deposit(new anchor.BN(2_000_000_000), Array.from(address))
.accounts({})
.rpc();

const provider = new ethers.JsonRpcProvider(`http://127.0.0.1:${port}`);
provider.pollingInterval = 100;
// anvil test mnemonic
Expand Down
71 changes: 71 additions & 0 deletions packages/localnet/src/setupSolana.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import { exec } from "child_process";
import util from "util";
import * as anchor from "@coral-xyz/anchor";
import Gateway_IDL from "./solana/idl/gateway.json";
import * as fs from "fs";
import { keccak256 } from "ethereumjs-util";
import { ec as EC } from "elliptic";
import path from "path";

const execAsync = util.promisify(exec);

process.env.ANCHOR_WALLET = path.resolve(
process.env.HOME || process.env.USERPROFILE || "",
".config/solana/id.json"
);
process.env.ANCHOR_PROVIDER_URL = "http://localhost:8899";

const keypairFilePath =
"./packages/localnet/src/solana/deploy/gateway-keypair.json";

const ec = new EC("secp256k1");

const tssKeyPair = ec.keyFromPrivate(
"5b81cdf52ba0766983acf8dd0072904733d92afe4dd3499e83e879b43ccb73e8"
);

const chain_id = 111111;
const chain_id_bn = new anchor.BN(chain_id);

export const setupSolana = async () => {
const gatewaySO = "./packages/localnet/src/solana/deploy/gateway.so";
console.log(`Deploying Solana program: ${gatewaySO}`);

try {
if (!fs.existsSync(keypairFilePath)) {
throw new Error(`Keypair file not found: ${keypairFilePath}`);
}

const publicKeyBuffer = Buffer.from(
tssKeyPair.getPublic(false, "hex").slice(2),
"hex"
);

const addressBuffer = keccak256(publicKeyBuffer);
const address = addressBuffer.slice(-20);
const tssAddress = Array.from(address);

anchor.setProvider(anchor.AnchorProvider.local());

const deployCommand = `solana program deploy --program-id ${keypairFilePath} ${gatewaySO} --url localhost`;
console.log(`Running command: ${deployCommand}`);

const { stdout } = await execAsync(deployCommand);
console.log(`Deployment output: ${stdout}`);

await new Promise((r) => setTimeout(r, 1000));

const gatewayProgram = new anchor.Program(Gateway_IDL as anchor.Idl);

await gatewayProgram.methods.initialize(tssAddress, chain_id_bn).rpc();
console.log("Initialized gateway program");

return { gatewayProgram, address };
} catch (error: any) {
console.error(`Deployment error: ${error.message}`);
if (error.logs) {
console.error("Logs:", error.logs);
}
throw error;
}
};
1 change: 1 addition & 0 deletions packages/localnet/src/solana/deploy/gateway-keypair.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
[148,138,110,3,169,253,42,101,79,110,149,110,112,214,41,163,75,28,36,29,241,151,41,200,135,185,252,180,158,191,166,156,119,192,217,18,69,149,119,145,212,43,144,149,176,111,89,140,102,63,193,127,241,148,51,161,170,62,19,196,239,253,6,192]
Binary file not shown.
Loading