diff --git a/.github/Solana-key.json b/.github/Solana-key.json new file mode 100644 index 00000000..2bb981bb --- /dev/null +++ b/.github/Solana-key.json @@ -0,0 +1 @@ +[156,214,52,226,101,141,187,127,80,230,163,132,41,11,225,162,81,118,242,213,213,115,202,74,97,141,5,10,174,133,85,224,183,10,143,212,142,103,199,43,238,47,236,199,89,218,36,117,140,129,195,8,60,178,93,132,86,200,130,56,251,157,235,138] \ No newline at end of file diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml new file mode 100644 index 00000000..61c34fc1 --- /dev/null +++ b/.github/workflows/e2e.yml @@ -0,0 +1,58 @@ +name: E2E Test Workflow + +on: + push: + + workflow_dispatch: + +jobs: + e2e-test: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Install Foundry + uses: foundry-rs/foundry-toolchain@v1 + + - name: Install Solana CLI + run: | + sh -c "$(curl -sSfL https://release.anza.xyz/stable/install)" + + - name: Ensure PATH includes Solana + run: echo "$HOME/.local/share/solana/install/active_release/bin" >> $GITHUB_PATH + + - name: Check solana version + run: solana --version + + - name: Start Solana Test Validator + run: | + solana-test-validator --reset --rpc-port 8899 --limit-ledger-size 50000000 --url https://api.devnet.solana.com \ + --clone ETGtqwDKEm1Z9gq6FdvYUfyDuUZr7g4UdPSmyNLVGriX \ + --clone 7UVimffxr9ow1uXYxsr4LHAcV58mLzhmwaeKvJ1pjLiE & + + - name: Install Anchor CLI + run: cargo install --git https://github.com/coral-xyz/anchor avm --locked --force + - name: Add Anchor to PATH + run: echo "$HOME/.cargo/bin" >> $GITHUB_PATH + - name: Install Anchor CLI + run: avm install latest + + - name: Use Anchor CLI + run: avm use latest + + + - name: Wait for validator to start + run: sleep 10 + + - name: Set Solana Keypair + run: cp $(pwd)/.github/Solana-key.json /home/runner/.config/solana/id.json + + - name: Run E2E Tests + run: make e2e + env: + PATH: $HOME/.local/share/solana/install/active_release/bin:/usr/local/bin:/usr/bin:/bin + + - name: Stop Solana Test Validator + run: pkill solana-test-validator || true diff --git a/.github/workflows/id.json b/.github/workflows/id.json new file mode 100644 index 00000000..2bb981bb --- /dev/null +++ b/.github/workflows/id.json @@ -0,0 +1 @@ +[156,214,52,226,101,141,187,127,80,230,163,132,41,11,225,162,81,118,242,213,213,115,202,74,97,141,5,10,174,133,85,224,183,10,143,212,142,103,199,43,238,47,236,199,89,218,36,117,140,129,195,8,60,178,93,132,86,200,130,56,251,157,235,138] \ No newline at end of file diff --git a/.gitignore b/.gitignore index 63056fd1..c80834d8 100755 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,11 @@ configs/logs.json dist/ build/ testnet/*/binary +contracts-tmp/ +*node_modules +push-chain-interop-contracts/ + + # Create cosmos app web/ diff --git a/Dockerfile.e2e b/Dockerfile.e2e new file mode 100644 index 00000000..79d918c6 --- /dev/null +++ b/Dockerfile.e2e @@ -0,0 +1,27 @@ +FROM golang:1.23 AS build +WORKDIR /app + +COPY go.mod go.sum ./ +RUN go mod download +COPY . . +RUN make install # regular build (dynamic link) + +FROM ubuntu:22.04 +RUN apt-get update && apt-get install -y bash curl jq git make && rm -rf /var/lib/apt/lists/* + +# Install wasmvm v1.5.4 shared library +RUN curl -L https://github.com/CosmWasm/wasmvm/releases/download/v1.5.4/libwasmvm.aarch64.so \ + -o /usr/lib/libwasmvm.aarch64.so && chmod 755 /usr/lib/libwasmvm.aarch64.so + +RUN curl -L https://github.com/CosmWasm/wasmvm/releases/download/v1.5.4/libwasmvm.x86_64.so \ + -o /usr/lib/libwasmvm.x86_64.so && chmod 755 /usr/lib/libwasmvm.x86_64.so + +COPY --from=build /go/bin/pchaind /usr/local/bin/pchaind +COPY scripts /app/scripts +WORKDIR /app + +ENV CHAIN_ID=localchain_9000-1 \ + BLOCK_TIME=1000ms \ + CLEAN=true + +CMD ["bash", "scripts/test_node_e2e.sh"] diff --git a/Makefile b/Makefile index 6d3dad48..dacd5860 100755 --- a/Makefile +++ b/Makefile @@ -370,3 +370,126 @@ help: @echo " generate-webapp : Create a new webapp template" .PHONY: help + +############################################################################### +### e2e... ### +############################################################################### + +# ------------------------ +# Docker commands (from before) +# ------------------------ +docker-build: + docker build -t push-chain-node -f Dockerfile.e2e . + +docker-up: + docker compose -f docker-compose.yml up --build -d + +docker-down: + docker compose -f docker-compose.yml down + +docker-logs: + docker compose -f docker-compose.yml logs -f + +docker-reset: + docker system prune -a --volumes -f + + +# ------------------------ +# Docker Setup flow +# ------------------------ + +ANVIL_URL=http://anvil:9545 +PUSH_EVM_URL=http://push-chain-node:8545 +CHAIN_RPC=http://push-chain-node:26657 +CHAIN_ID=localchain_9000-1 + +# Path where contracts will be cloned +CONTRACTS_DIR := contracts-tmp +INTEROP_REPO := https://github.com/pushchain/push-chain-interop-contracts.git/ +CORE_REPO := https://github.com/pushchain/push-chain-core-contracts.git +SDK_REPO := https://github.com/pushchain/push-chain-sdk.git +E2E_DIR := e2e + +e2e: docker-up wait-for-services fund-acc1 deploy-interop deploy-core e2e-solana-interop-deployment e2e-solana-chain-config e2e-run-test + +# Wait for services to start up +wait-for-services: + @echo "Waiting for Anvil and Push-Chain-Node to start..." + @for i in {1..30}; do \ + if docker exec push-chain-node curl -s --fail http://push-chain-node:26657/status; then \ + echo "Push-Chain Node is ready"; \ + break; \ + fi; \ + echo "Waiting for Push-Chain Node..."; \ + sleep 2; \ + done + docker logs push-chain-node + +# Fund acc1 on push-chain +fund-acc1: + @echo "waiting for Push-chain-node to setup" + sleep 10 + @echo "Funding acc1 on push-chain..." + docker exec push-chain-node pchaind tx bank send push1j0v5urpud7kwsk9zgz2tc0v9d95ct6t5qxv38h \ + push1w7xnyp3hf79vyetj3cvw8l32u6unun8yr6zn60 \ + 1000000000000000000upc \ + --gas-prices 100000000000upc \ + --node http://push-chain-node:26657 \ + -y + + +# Deploy the interop contract and capture address +deploy-interop: + echo "Adding Sepolia config to push-chain" && \ + docker exec push-chain-node pchaind tx uregistry add-chain-config \ + --chain-config "$$(cat e2e/eth_sepolia_e2e_chain_config.json)" \ + --from acc1 \ + --gas-prices 100000000000upc -y + +# Deploy push-core-contracts using forge script +deploy-core: + @echo "Deploying Push Core Contracts..." + @rm -rf $(CONTRACTS_DIR) && mkdir $(CONTRACTS_DIR) + cd $(CONTRACTS_DIR) && git clone $(CORE_REPO) + cd $(CONTRACTS_DIR)/push-chain-core-contracts && git submodule update --init --recursive + cd $(CONTRACTS_DIR)/push-chain-core-contracts && forge install && forge build + cd $(CONTRACTS_DIR)/push-chain-core-contracts && forge script scripts/deployFactory.s.sol \ + --broadcast \ + --rpc-url http://localhost:8545 \ + --private-key 0x0dfb3d814afd8d0bf7a6010e8dd2b6ac835cabe4da9e2c1e80c6a14df3994dd4 \ + --slow + + cd $(CONTRACTS_DIR)/push-chain-core-contracts && forge script scripts/deployMock.s.sol --broadcast --rpc-url http://localhost:8545 --private-key 0x0dfb3d814afd8d0bf7a6010e8dd2b6ac835cabe4da9e2c1e80c6a14df3994dd4 --slow + +e2e-solana-chain-config: + echo "Adding Solana config to push-chain" + docker exec push-chain-node pchaind tx uregistry add-chain-config --chain-config "$$(cat e2e/solana_localchain_chain_config.json)" --from acc1 --gas-prices 100000000000upc -y + +e2e-solana-interop-deployment: + @echo "Funding local solana account" + solana airdrop 10 DKWx5ZiKpmdzu7s11JR93cw69PEJZkHAZpg6BNoHjVmK --url http://127.0.0.1:8899 + @echo "Setting Solana CLI to local validator..." + cd $(E2E_DIR) && rm -rf push-chain-interop-contracts + solana config set --url http://127.0.0.1:8899 + @echo "Deploying svm_gateway contract on solana-test-validator" + cp $(E2E_DIR)/.env.sample $(E2E_DIR)/.env + cd $(E2E_DIR) && git clone $(INTEROP_REPO) + cp $(E2E_DIR)/deploy.sh $(E2E_DIR)/push-chain-interop-contracts/contracts/svm-gateway/deploy.sh + cd $(E2E_DIR)/push-chain-interop-contracts/contracts/svm-gateway && ./deploy.sh localnet + + @echo "Initializing account and funding vault..." + cd $(E2E_DIR)/solana-setup && npm install + + @cd $(E2E_DIR)/solana-setup && VAULT=$$(npx ts-node --compiler-options '{"module":"commonjs"}' ./index.ts | grep 'vaultbalance' | awk '{print $$2}'); \ + echo "Vault PDA is $$VAULT"; \ + solana airdrop 10 $$VAULT --url http://127.0.0.1:8899 + + +e2e-run-test: + @echo "Cloning e2e repository..." + @rm -rf $(CONTRACTS_DIR)/push-chain-sdk + cd $(CONTRACTS_DIR) && git clone $(SDK_REPO) + cd $(CONTRACTS_DIR)/push-chain-sdk && git checkout push-node-e2e-test && yarn install + cp $(E2E_DIR)/push-chain-interop-contracts/contracts/svm-gateway/target/idl/pushsolanalocker.json $(CONTRACTS_DIR)/push-chain-sdk/packages/core/src/lib/constants/abi/feeLocker.json + cp $(E2E_DIR)/.env $(CONTRACTS_DIR)/push-chain-sdk/packages/core/.env + cd $(CONTRACTS_DIR)/push-chain-sdk && npx jest core/__e2e__/pushchain.spec.ts --runInBand --detectOpenHandles diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 00000000..965b06e0 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,38 @@ +version: '3.8' + +services: + anvil: + image: ghcr.io/foundry-rs/foundry:v1.2.3 + ports: + - "9545:9545" + networks: + - pushnet + entrypoint: ["anvil"] + command: ["--host", "0.0.0.0", "--port", "9545", "--chain-id", "11155111", "--fork-url", "https://ethereum-sepolia-rpc.publicnode.com", "--block-time", "1"] + + push-chain-node: + build: + context: . + dockerfile: Dockerfile.e2e + container_name: push-chain-node + environment: + - CHAIN_ID=localchain_9000-1 + - BLOCK_TIME=1000ms + - CLEAN=true + command: bash scripts/test_node_e2e.sh + extra_hosts: + - "host.docker.internal:host-gateway" + ports: + - "26657:26657" # Tendermint RPC + - "1317:1317" # Cosmos REST API + - "8545:8545" # Cosmos REST API + networks: + - pushnet + depends_on: + - anvil + volumes: + - ./scripts:/app/scripts + +networks: + pushnet: + driver: bridge diff --git a/e2e/.env.sample b/e2e/.env.sample new file mode 100644 index 00000000..9955977c --- /dev/null +++ b/e2e/.env.sample @@ -0,0 +1,47 @@ +# ENV files is required to run test cases + + + + + + + +## EVM and Solana- Make sure this pk has funds on the selected network - otherwise some tests would be skipped + + + + + +EVM_PRIVATE_KEY=0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 + + + + + +EVM_RPC=http://localhost:9545 + + + + + +SOLANA_RPC_URL=http://10.1.0.1:8899 + + + + + +SOLANA_PRIVATE_KEY=48sPd9RUgvzbv3poq9jhbh4afHcHK7SxTuAUdjTeeM28TFc1SCpgtDCf3ofx6virpG5XNCrZsMnzKaZiHiK2HTuB + + + + + +PUSH_PRIVATE_KEY=0x0dfb3d814afd8d0bf7a6010e8dd2b6ac835cabe4da9e2c1e80c6a14df3994dd4 + + + +SOLANA_PRIVATE_KEY_HEX=9cd634e2658dbb7f50e6a384290be1a25176f2d5d573ca4a618d050aae8555e0b70a8fd48e67c72bee2fecc759da24758c81c3083cb25d8456c88238fb9deb8a + + + + diff --git a/e2e/deploy.sh b/e2e/deploy.sh new file mode 100755 index 00000000..d7353e40 --- /dev/null +++ b/e2e/deploy.sh @@ -0,0 +1,47 @@ +#!/bin/bash + +set -e + +# Usage: ./deploy.sh devnet +CLUSTER="$1" + +if [[ -z "$CLUSTER" ]]; then + echo "❌ Please specify the cluster to deploy to (e.g., devnet, testnet, localnet, mainnet-beta)" + exit 1 +fi + +# Optional: Custom keypair path (change this if needed) +KEYPAIR_PATH="$HOME/.config/solana/id.json" + +echo "🔐 Using keypair: $KEYPAIR_PATH" + +echo "📦 Building program..." +anchor build + +echo "🚀 Deploying to $CLUSTER..." +solana config set --keypair "$KEYPAIR_PATH" --url "http://localhost:8899" + +# Capture the output of anchor deploy +DEPLOY_OUTPUT=$(anchor deploy --provider.cluster "$CLUSTER" --provider.wallet "$KEYPAIR_PATH") + +# Extract the program ID from the output +PROGRAM_ID=$(echo "$DEPLOY_OUTPUT" | grep "Program Id" | awk '{print $3}') + +if [[ -z "$PROGRAM_ID" ]]; then + echo "❌ Failed to extract Program ID from deploy output!" + exit 1 +fi + +echo "🆔 Program ID: $PROGRAM_ID" + +# Append program ID to .env files +echo "SOLANA_PROGRAM_ID=$PROGRAM_ID" >> ../../../.env +echo "SOLANA_PROGRAM_ID=$PROGRAM_ID" >> ../../../solana-setup/.env + +cp target/idl/pushsolanalocker.json ../../../solana-setup/pushsolanalocker.json +cp target/types/pushsolanalocker.ts ../../../solana-setup/type_pushsolanalocker.ts + +jq --arg addr "$PROGRAM_ID" '.gateway_address = $addr' ../../../solana_localchain_chain_config.json > tmp.json && mv tmp.json ../../../solana_localchain_chain_config.json + + +echo "✅ Successfully deployed to $CLUSTER" diff --git a/e2e/eth_sepolia_e2e_chain_config.json b/e2e/eth_sepolia_e2e_chain_config.json new file mode 100644 index 00000000..a5a35187 --- /dev/null +++ b/e2e/eth_sepolia_e2e_chain_config.json @@ -0,0 +1,28 @@ +{ + "chain": "eip155:11155111", + "public_rpc_url": "http://anvil:9545", + "vm_type": 1, + "gateway_address": "0x05bD7a3D18324c1F7e216f7fBF2b15985aE5281A", + "block_confirmation": { + "fast_inbound": 0, + "standard_inbound": 2 + }, + "gateway_methods": [ + { + "name": "sendFunds", + "identifier": "0x65f4dbe1", + "event_identifier": "0x313800e2e529b7d45906548dd908bb537772d390b660787b2a929ddf1facf6e4", + "confirmation_type": 1 + }, + { + "name": "addFunds", + "identifier": "0xf9bfe8a7", + "event_identifier": "0xb28f49668e7e76dc96d7aabe5b7f63fecfbd1c3574774c05e8204e749fd96fbd", + "confirmation_type": 2 + } + ], + "enabled": { + "isInboundEnabled": true, + "isOutboundEnabled": true + } +} \ No newline at end of file diff --git a/e2e/solana-setup/index.ts b/e2e/solana-setup/index.ts new file mode 100644 index 00000000..80fa663b --- /dev/null +++ b/e2e/solana-setup/index.ts @@ -0,0 +1,68 @@ +import fs from "fs"; +import * as anchor from "@coral-xyz/anchor"; +import "dotenv/config"; +import { PublicKey, SystemProgram, Keypair, Connection } from "@solana/web3.js"; +import { Pushsolanalocker } from "./type_pushsolanalocker"; + +(async () => { + // 1. Load admin keypair explicitly + const secret: number[] = JSON.parse( + fs.readFileSync(`${process.env.HOME}/.config/solana/id.json`, "utf8") + ); + const adminKeypair = Keypair.fromSecretKey(Uint8Array.from(secret)); + const admin: PublicKey = adminKeypair.publicKey; + + // 2. Create provider manually + const connection = new Connection("http://127.0.0.1:8899", "confirmed"); + const wallet = new anchor.Wallet(adminKeypair); + const provider = new anchor.AnchorProvider(connection, wallet, { + commitment: "confirmed", + }); + anchor.setProvider(provider); + + // 3. Load program + const PROGRAM_ID = new PublicKey(process.env['SOLANA_PROGRAM_ID'] as string); + console.log("hmml", PROGRAM_ID) + const idl = JSON.parse(fs.readFileSync("pushsolanalocker.json", "utf8")); + const program = new anchor.Program(idl as Pushsolanalocker, provider) + console.log("Program loaded:", program.programId.toBase58()); + + // 4. Derive PDAs + const [lockerPda] = PublicKey.findProgramAddressSync( + [Buffer.from("locker")], + PROGRAM_ID + ); + const [vaultPda] = PublicKey.findProgramAddressSync( + [Buffer.from("vault")], + PROGRAM_ID + ); + + // 5. Initialize if not already created + console.log("2. Initializing locker..."); + const lockerAccount = await connection.getAccountInfo(lockerPda); + console.log(lockerPda) + console.log("localaccount", lockerAccount) + + const vaultbalance = await connection.getBalance(vaultPda); + console.log("vaultbalance", vaultPda.toBase58()) + const lockerbalance = await connection.getBalance(lockerPda); + console.log("lockerbalance : ", lockerbalance); + + + if (!lockerAccount) { + const tx = await program.methods + .initialize() + .accounts({ + locker: lockerPda, // <-- Make sure this matches your IDL account names + vault: vaultPda, + admin: admin, + systemProgram: SystemProgram.programId, + }) + .signers([adminKeypair]) // explicitly add signer + .rpc(); + + console.log(`✅ Locker initialized: ${tx}\n`); + } else { + console.log("✅ Locker already exists\n"); + } +})(); diff --git a/e2e/solana-setup/package-lock.json b/e2e/solana-setup/package-lock.json new file mode 100644 index 00000000..6ab585c8 --- /dev/null +++ b/e2e/solana-setup/package-lock.json @@ -0,0 +1,763 @@ +{ + "name": "solana-setup", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "dependencies": { + "@coral-xyz/anchor": "^0.31.1", + "dotenv": "^17.2.1" + } + }, + "node_modules/@babel/runtime": { + "version": "7.28.3", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.3.tgz", + "integrity": "sha512-9uIQ10o0WGdpP6GDhXcdOJPJuDgFtIDtN/9+ArJQ2NAfAmiuhTQdzkaTGR33v43GYS2UrSA0eX2pPPHoFVvpxA==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@coral-xyz/anchor": { + "version": "0.31.1", + "resolved": "https://registry.npmjs.org/@coral-xyz/anchor/-/anchor-0.31.1.tgz", + "integrity": "sha512-QUqpoEK+gi2S6nlYc2atgT2r41TT3caWr/cPUEL8n8Md9437trZ68STknq897b82p5mW0XrTBNOzRbmIRJtfsA==", + "license": "(MIT OR Apache-2.0)", + "dependencies": { + "@coral-xyz/anchor-errors": "^0.31.1", + "@coral-xyz/borsh": "^0.31.1", + "@noble/hashes": "^1.3.1", + "@solana/web3.js": "^1.69.0", + "bn.js": "^5.1.2", + "bs58": "^4.0.1", + "buffer-layout": "^1.2.2", + "camelcase": "^6.3.0", + "cross-fetch": "^3.1.5", + "eventemitter3": "^4.0.7", + "pako": "^2.0.3", + "superstruct": "^0.15.4", + "toml": "^3.0.0" + }, + "engines": { + "node": ">=17" + } + }, + "node_modules/@coral-xyz/anchor-errors": { + "version": "0.31.1", + "resolved": "https://registry.npmjs.org/@coral-xyz/anchor-errors/-/anchor-errors-0.31.1.tgz", + "integrity": "sha512-NhNEku4F3zzUSBtrYz84FzYWm48+9OvmT1Hhnwr6GnPQry2dsEqH/ti/7ASjjpoFTWRnPXrjAIT1qM6Isop+LQ==", + "license": "Apache-2.0", + "engines": { + "node": ">=10" + } + }, + "node_modules/@coral-xyz/borsh": { + "version": "0.31.1", + "resolved": "https://registry.npmjs.org/@coral-xyz/borsh/-/borsh-0.31.1.tgz", + "integrity": "sha512-9N8AU9F0ubriKfNE3g1WF0/4dtlGXoBN/hd1PvbNBamBNwRgHxH4P+o3Zt7rSEloW1HUs6LfZEchlx9fW7POYw==", + "license": "Apache-2.0", + "dependencies": { + "bn.js": "^5.1.2", + "buffer-layout": "^1.2.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@solana/web3.js": "^1.69.0" + } + }, + "node_modules/@noble/curves": { + "version": "1.9.7", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.9.7.tgz", + "integrity": "sha512-gbKGcRUYIjA3/zCCNaWDciTMFI0dCkvou3TL8Zmy5Nc7sJ47a0jtOeZoTaMxkuqRo9cRhjOdZJXegxYE5FN/xw==", + "license": "MIT", + "dependencies": { + "@noble/hashes": "1.8.0" + }, + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@noble/hashes": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.8.0.tgz", + "integrity": "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==", + "license": "MIT", + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@solana/buffer-layout": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@solana/buffer-layout/-/buffer-layout-4.0.1.tgz", + "integrity": "sha512-E1ImOIAD1tBZFRdjeM4/pzTiTApC0AOBGwyAMS4fwIodCWArzJ3DWdoh8cKxeFM2fElkxBh2Aqts1BPC373rHA==", + "license": "MIT", + "dependencies": { + "buffer": "~6.0.3" + }, + "engines": { + "node": ">=5.10" + } + }, + "node_modules/@solana/codecs-core": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@solana/codecs-core/-/codecs-core-2.3.0.tgz", + "integrity": "sha512-oG+VZzN6YhBHIoSKgS5ESM9VIGzhWjEHEGNPSibiDTxFhsFWxNaz8LbMDPjBUE69r9wmdGLkrQ+wVPbnJcZPvw==", + "license": "MIT", + "dependencies": { + "@solana/errors": "2.3.0" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" + } + }, + "node_modules/@solana/codecs-numbers": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@solana/codecs-numbers/-/codecs-numbers-2.3.0.tgz", + "integrity": "sha512-jFvvwKJKffvG7Iz9dmN51OGB7JBcy2CJ6Xf3NqD/VP90xak66m/Lg48T01u5IQ/hc15mChVHiBm+HHuOFDUrQg==", + "license": "MIT", + "dependencies": { + "@solana/codecs-core": "2.3.0", + "@solana/errors": "2.3.0" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" + } + }, + "node_modules/@solana/errors": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@solana/errors/-/errors-2.3.0.tgz", + "integrity": "sha512-66RI9MAbwYV0UtP7kGcTBVLxJgUxoZGm8Fbc0ah+lGiAw17Gugco6+9GrJCV83VyF2mDWyYnYM9qdI3yjgpnaQ==", + "license": "MIT", + "dependencies": { + "chalk": "^5.4.1", + "commander": "^14.0.0" + }, + "bin": { + "errors": "bin/cli.mjs" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" + } + }, + "node_modules/@solana/web3.js": { + "version": "1.98.4", + "resolved": "https://registry.npmjs.org/@solana/web3.js/-/web3.js-1.98.4.tgz", + "integrity": "sha512-vv9lfnvjUsRiq//+j5pBdXig0IQdtzA0BRZ3bXEP4KaIyF1CcaydWqgyzQgfZMNIsWNWmG+AUHwPy4AHOD6gpw==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.25.0", + "@noble/curves": "^1.4.2", + "@noble/hashes": "^1.4.0", + "@solana/buffer-layout": "^4.0.1", + "@solana/codecs-numbers": "^2.1.0", + "agentkeepalive": "^4.5.0", + "bn.js": "^5.2.1", + "borsh": "^0.7.0", + "bs58": "^4.0.1", + "buffer": "6.0.3", + "fast-stable-stringify": "^1.0.0", + "jayson": "^4.1.1", + "node-fetch": "^2.7.0", + "rpc-websockets": "^9.0.2", + "superstruct": "^2.0.2" + } + }, + "node_modules/@solana/web3.js/node_modules/superstruct": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/superstruct/-/superstruct-2.0.2.tgz", + "integrity": "sha512-uV+TFRZdXsqXTL2pRvujROjdZQ4RAlBUS5BTh9IGm+jTqQntYThciG/qu57Gs69yjnVUSqdxF9YLmSnpupBW9A==", + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@swc/helpers": { + "version": "0.5.17", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.17.tgz", + "integrity": "sha512-5IKx/Y13RsYd+sauPb2x+U/xZikHjolzfuDgTAl/Tdf3Q8rslRvC19NKDLgAJQ6wsqADk10ntlv08nPFw/gO/A==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.8.0" + } + }, + "node_modules/@types/connect": { + "version": "3.4.38", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", + "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/node": { + "version": "12.20.55", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.55.tgz", + "integrity": "sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==", + "license": "MIT" + }, + "node_modules/@types/uuid": { + "version": "8.3.4", + "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-8.3.4.tgz", + "integrity": "sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw==", + "license": "MIT" + }, + "node_modules/@types/ws": { + "version": "7.4.7", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-7.4.7.tgz", + "integrity": "sha512-JQbbmxZTZehdc2iszGKs5oC3NFnjeay7mtAWrdt7qNtAVK0g19muApzAy4bm9byz79xa2ZnO/BOBC2R8RC5Lww==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/agentkeepalive": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.6.0.tgz", + "integrity": "sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ==", + "license": "MIT", + "dependencies": { + "humanize-ms": "^1.2.1" + }, + "engines": { + "node": ">= 8.0.0" + } + }, + "node_modules/base-x": { + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.11.tgz", + "integrity": "sha512-xz7wQ8xDhdyP7tQxwdteLYeFfS68tSMNCZ/Y37WJ4bhGfKPpqEIlmIyueQHqOyoPhE6xNUqjzRr8ra0eF9VRvA==", + "license": "MIT", + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/bn.js": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.2.tgz", + "integrity": "sha512-v2YAxEmKaBLahNwE1mjp4WON6huMNeuDvagFZW+ASCuA/ku0bXR9hSMw0XpiqMoA3+rmnyck/tPRSFQkoC9Cuw==", + "license": "MIT" + }, + "node_modules/borsh": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/borsh/-/borsh-0.7.0.tgz", + "integrity": "sha512-CLCsZGIBCFnPtkNnieW/a8wmreDmfUtjU2m9yHrzPXIlNbqVs0AQrSatSG6vdNYUqdc83tkQi2eHfF98ubzQLA==", + "license": "Apache-2.0", + "dependencies": { + "bn.js": "^5.2.0", + "bs58": "^4.0.0", + "text-encoding-utf-8": "^1.0.2" + } + }, + "node_modules/bs58": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/bs58/-/bs58-4.0.1.tgz", + "integrity": "sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw==", + "license": "MIT", + "dependencies": { + "base-x": "^3.0.2" + } + }, + "node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/buffer-layout": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/buffer-layout/-/buffer-layout-1.2.2.tgz", + "integrity": "sha512-kWSuLN694+KTk8SrYvCqwP2WcgQjoRCiF5b4QDvkkz8EmgD+aWAIceGFKMIAdmF/pH+vpgNV3d3kAKorcdAmWA==", + "license": "MIT", + "engines": { + "node": ">=4.5" + } + }, + "node_modules/bufferutil": { + "version": "4.0.9", + "resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-4.0.9.tgz", + "integrity": "sha512-WDtdLmJvAuNNPzByAYpRo2rF1Mmradw6gvWsQKf63476DDXmomT9zUiGypLcG4ibIM67vhAj8jJRdbmEws2Aqw==", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "dependencies": { + "node-gyp-build": "^4.3.0" + }, + "engines": { + "node": ">=6.14.2" + } + }, + "node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/chalk": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.0.tgz", + "integrity": "sha512-46QrSQFyVSEyYAgQ22hQ+zDa60YHA4fBstHmtSApj1Y5vKtG27fWowW03jCk5KcbXEWPZUIR894aARCA/G1kfQ==", + "license": "MIT", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/commander": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-14.0.0.tgz", + "integrity": "sha512-2uM9rYjPvyq39NwLRqaiLtWHyDC1FvryJDa2ATTVims5YAS4PupsEQsDvP14FqhFr0P49CYDugi59xaxJlTXRA==", + "license": "MIT", + "engines": { + "node": ">=20" + } + }, + "node_modules/cross-fetch": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.2.0.tgz", + "integrity": "sha512-Q+xVJLoGOeIMXZmbUK4HYk+69cQH6LudR0Vu/pRm2YlU/hDV9CiS0gKUMaWY5f2NeUH9C1nV3bsTlCo0FsTV1Q==", + "license": "MIT", + "dependencies": { + "node-fetch": "^2.7.0" + } + }, + "node_modules/delay": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/delay/-/delay-5.0.0.tgz", + "integrity": "sha512-ReEBKkIfe4ya47wlPYf/gu5ib6yUG0/Aez0JQZQz94kiWtRQvZIQbTiehsnwHvLSWJnQdhVeqYue7Id1dKr0qw==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/dotenv": { + "version": "17.2.1", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.2.1.tgz", + "integrity": "sha512-kQhDYKZecqnM0fCnzI5eIv5L4cAe/iRI+HqMbO/hbRdTAeXDG+M9FjipUxNfbARuEg4iHIbhnhs78BCHNbSxEQ==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, + "node_modules/es6-promise": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", + "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==", + "license": "MIT" + }, + "node_modules/es6-promisify": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", + "integrity": "sha512-C+d6UdsYDk0lMebHNR4S2NybQMMngAOnOwYBQjTOiv0MkoJMP0Myw2mgpDLBcpfCmRLxyFqYhS/CfOENq4SJhQ==", + "license": "MIT", + "dependencies": { + "es6-promise": "^4.0.3" + } + }, + "node_modules/eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", + "license": "MIT" + }, + "node_modules/eyes": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/eyes/-/eyes-0.1.8.tgz", + "integrity": "sha512-GipyPsXO1anza0AOZdy69Im7hGFCNB7Y/NGjDlZGJ3GJJLtwNSb2vrzYrTYJRrRloVx7pl+bhUaTB8yiccPvFQ==", + "engines": { + "node": "> 0.1.90" + } + }, + "node_modules/fast-stable-stringify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fast-stable-stringify/-/fast-stable-stringify-1.0.0.tgz", + "integrity": "sha512-wpYMUmFu5f00Sm0cj2pfivpmawLZ0NKdviQ4w9zJeR8JVtOpOxHmLaJuj0vxvGqMJQWyP/COUkF75/57OKyRag==", + "license": "MIT" + }, + "node_modules/humanize-ms": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", + "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==", + "license": "MIT", + "dependencies": { + "ms": "^2.0.0" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/isomorphic-ws": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/isomorphic-ws/-/isomorphic-ws-4.0.1.tgz", + "integrity": "sha512-BhBvN2MBpWTaSHdWRb/bwdZJ1WaehQ2L1KngkCkfLUGF0mAWAT1sQUQacEmQ0jXkFw/czDXPNQSL5u2/Krsz1w==", + "license": "MIT", + "peerDependencies": { + "ws": "*" + } + }, + "node_modules/jayson": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/jayson/-/jayson-4.2.0.tgz", + "integrity": "sha512-VfJ9t1YLwacIubLhONk0KFeosUBwstRWQ0IRT1KDjEjnVnSOVHC3uwugyV7L0c7R9lpVyrUGT2XWiBA1UTtpyg==", + "license": "MIT", + "dependencies": { + "@types/connect": "^3.4.33", + "@types/node": "^12.12.54", + "@types/ws": "^7.4.4", + "commander": "^2.20.3", + "delay": "^5.0.0", + "es6-promisify": "^5.0.0", + "eyes": "^0.1.8", + "isomorphic-ws": "^4.0.1", + "json-stringify-safe": "^5.0.1", + "stream-json": "^1.9.1", + "uuid": "^8.3.2", + "ws": "^7.5.10" + }, + "bin": { + "jayson": "bin/jayson.js" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jayson/node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "license": "MIT" + }, + "node_modules/json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", + "license": "ISC" + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "license": "MIT", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/node-gyp-build": { + "version": "4.8.4", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.4.tgz", + "integrity": "sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==", + "license": "MIT", + "optional": true, + "bin": { + "node-gyp-build": "bin.js", + "node-gyp-build-optional": "optional.js", + "node-gyp-build-test": "build-test.js" + } + }, + "node_modules/pako": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/pako/-/pako-2.1.0.tgz", + "integrity": "sha512-w+eufiZ1WuJYgPXbV/PO3NCMEc3xqylkKHzp8bxp1uW4qaSNQUkwmLLEc3kKsfz8lpV1F8Ht3U1Cm+9Srog2ug==", + "license": "(MIT AND Zlib)" + }, + "node_modules/rpc-websockets": { + "version": "9.1.3", + "resolved": "https://registry.npmjs.org/rpc-websockets/-/rpc-websockets-9.1.3.tgz", + "integrity": "sha512-I+kNjW0udB4Fetr3vvtRuYZJS0PcSPyyvBcH5sDdoV8DFs5E4W2pTr7aiMlKfPxANTClP9RlqCPolj9dd5MsEA==", + "license": "LGPL-3.0-only", + "dependencies": { + "@swc/helpers": "^0.5.11", + "@types/uuid": "^8.3.4", + "@types/ws": "^8.2.2", + "buffer": "^6.0.3", + "eventemitter3": "^5.0.1", + "uuid": "^8.3.2", + "ws": "^8.5.0" + }, + "funding": { + "type": "paypal", + "url": "https://paypal.me/kozjak" + }, + "optionalDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + } + }, + "node_modules/rpc-websockets/node_modules/@types/ws": { + "version": "8.18.1", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.18.1.tgz", + "integrity": "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/rpc-websockets/node_modules/eventemitter3": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", + "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==", + "license": "MIT" + }, + "node_modules/rpc-websockets/node_modules/ws": { + "version": "8.18.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz", + "integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/stream-chain": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/stream-chain/-/stream-chain-2.2.5.tgz", + "integrity": "sha512-1TJmBx6aSWqZ4tx7aTpBDXK0/e2hhcNSTV8+CbFJtDjbb+I1mZ8lHit0Grw9GRT+6JbIrrDd8esncgBi8aBXGA==", + "license": "BSD-3-Clause" + }, + "node_modules/stream-json": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/stream-json/-/stream-json-1.9.1.tgz", + "integrity": "sha512-uWkjJ+2Nt/LO9Z/JyKZbMusL8Dkh97uUBTv3AJQ74y07lVahLY4eEFsPsE97pxYBwr8nnjMAIch5eqI0gPShyw==", + "license": "BSD-3-Clause", + "dependencies": { + "stream-chain": "^2.2.5" + } + }, + "node_modules/superstruct": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/superstruct/-/superstruct-0.15.5.tgz", + "integrity": "sha512-4AOeU+P5UuE/4nOUkmcQdW5y7i9ndt1cQd/3iUe+LTz3RxESf/W/5lg4B74HbDMMv8PHnPnGCQFH45kBcrQYoQ==", + "license": "MIT" + }, + "node_modules/text-encoding-utf-8": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/text-encoding-utf-8/-/text-encoding-utf-8-1.0.2.tgz", + "integrity": "sha512-8bw4MY9WjdsD2aMtO0OzOCY3pXGYNx2d2FfHRVUKkiCPDWjKuOlhLVASS+pD7VkLTVjW268LYJHwsnPFlBpbAg==" + }, + "node_modules/toml": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/toml/-/toml-3.0.0.tgz", + "integrity": "sha512-y/mWCZinnvxjTKYhJ+pYxwD0mRLVvOtdS2Awbgxln6iEnt4rk0yBxeSBHkGJcPucRiG0e55mwWp+g/05rsrd6w==", + "license": "MIT" + }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "license": "MIT" + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" + }, + "node_modules/typescript": { + "version": "5.9.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.2.tgz", + "integrity": "sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==", + "license": "Apache-2.0", + "peer": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/utf-8-validate": { + "version": "5.0.10", + "resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.10.tgz", + "integrity": "sha512-Z6czzLq4u8fPOyx7TU6X3dvUZVvoJmxSQ+IcrlmagKhilxlhZgxPK6C5Jqbkw1IDUmFTM+cz9QDnnLTwDz/2gQ==", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "dependencies": { + "node-gyp-build": "^4.3.0" + }, + "engines": { + "node": ">=6.14.2" + } + }, + "node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "license": "MIT", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "license": "BSD-2-Clause" + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "license": "MIT", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/ws": { + "version": "7.5.10", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz", + "integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==", + "license": "MIT", + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + } + } +} diff --git a/e2e/solana-setup/package.json b/e2e/solana-setup/package.json new file mode 100644 index 00000000..bfb19b3a --- /dev/null +++ b/e2e/solana-setup/package.json @@ -0,0 +1,6 @@ +{ + "dependencies": { + "@coral-xyz/anchor": "^0.31.1", + "dotenv": "^17.2.1" + } +} diff --git a/e2e/solana-setup/pushsolanalocker.json b/e2e/solana-setup/pushsolanalocker.json new file mode 100644 index 00000000..26e634b3 --- /dev/null +++ b/e2e/solana-setup/pushsolanalocker.json @@ -0,0 +1,540 @@ +{ + "address": "H2sHWWnihK2bdtJoM79G737FmzzLuJv5WC1ModcCDSE3", + "metadata": { + "name": "pushsolanalocker", + "version": "0.1.0", + "spec": "0.1.0", + "description": "Created with Anchor" + }, + "instructions": [ + { + "name": "add_funds", + "discriminator": [ + 132, + 237, + 76, + 57, + 80, + 10, + 179, + 138 + ], + "accounts": [ + { + "name": "locker", + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 108, + 111, + 99, + 107, + 101, + 114 + ] + } + ] + } + }, + { + "name": "vault", + "writable": true, + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 118, + 97, + 117, + 108, + 116 + ] + } + ] + } + }, + { + "name": "user", + "writable": true, + "signer": true + }, + { + "name": "price_update" + }, + { + "name": "system_program", + "address": "11111111111111111111111111111111" + } + ], + "args": [ + { + "name": "amount", + "type": "u64" + }, + { + "name": "transaction_hash", + "type": { + "array": [ + "u8", + 32 + ] + } + } + ] + }, + { + "name": "get_sol_price", + "discriminator": [ + 230, + 145, + 206, + 175, + 43, + 184, + 97, + 110 + ], + "accounts": [ + { + "name": "price_update" + } + ], + "args": [], + "returns": { + "defined": { + "name": "PriceData" + } + } + }, + { + "name": "initialize", + "discriminator": [ + 175, + 175, + 109, + 31, + 13, + 152, + 155, + 237 + ], + "accounts": [ + { + "name": "locker_data", + "writable": true, + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 108, + 111, + 99, + 107, + 101, + 114 + ] + } + ] + } + }, + { + "name": "vault", + "writable": true, + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 118, + 97, + 117, + 108, + 116 + ] + } + ] + } + }, + { + "name": "admin", + "writable": true, + "signer": true + }, + { + "name": "system_program", + "address": "11111111111111111111111111111111" + } + ], + "args": [] + }, + { + "name": "recover_tokens", + "discriminator": [ + 156, + 18, + 205, + 212, + 197, + 254, + 126, + 142 + ], + "accounts": [ + { + "name": "locker_data" + }, + { + "name": "vault", + "writable": true, + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 118, + 97, + 117, + 108, + 116 + ] + } + ] + } + }, + { + "name": "recipient", + "writable": true, + "signer": true + }, + { + "name": "admin", + "writable": true, + "signer": true + }, + { + "name": "system_program", + "address": "11111111111111111111111111111111" + } + ], + "args": [ + { + "name": "amount", + "type": "u64" + } + ] + } + ], + "accounts": [ + { + "name": "Locker", + "discriminator": [ + 74, + 246, + 6, + 113, + 249, + 228, + 75, + 169 + ] + }, + { + "name": "PriceUpdateV2", + "discriminator": [ + 34, + 241, + 35, + 99, + 157, + 126, + 244, + 205 + ] + } + ], + "events": [ + { + "name": "FundsAddedEvent", + "discriminator": [ + 127, + 31, + 108, + 255, + 187, + 19, + 70, + 68 + ] + }, + { + "name": "TokenRecoveredEvent", + "discriminator": [ + 72, + 100, + 110, + 181, + 188, + 125, + 10, + 53 + ] + } + ], + "errors": [ + { + "code": 6000, + "name": "NoFundsSent", + "msg": "No SOL sent" + }, + { + "code": 6001, + "name": "Unauthorized", + "msg": "Unauthorized" + }, + { + "code": 6002, + "name": "InvalidPrice", + "msg": "Invalid price data" + } + ], + "types": [ + { + "name": "FundsAddedEvent", + "type": { + "kind": "struct", + "fields": [ + { + "name": "user", + "type": "pubkey" + }, + { + "name": "sol_amount", + "type": "u64" + }, + { + "name": "usd_equivalent", + "type": "i128" + }, + { + "name": "usd_exponent", + "type": "i32" + }, + { + "name": "transaction_hash", + "type": { + "array": [ + "u8", + 32 + ] + } + } + ] + } + }, + { + "name": "Locker", + "type": { + "kind": "struct", + "fields": [ + { + "name": "admin", + "type": "pubkey" + }, + { + "name": "bump", + "type": "u8" + }, + { + "name": "vault_bump", + "type": "u8" + } + ] + } + }, + { + "name": "PriceData", + "type": { + "kind": "struct", + "fields": [ + { + "name": "price", + "type": "i64" + }, + { + "name": "exponent", + "type": "i32" + }, + { + "name": "publish_time", + "type": "i64" + }, + { + "name": "confidence", + "type": "u64" + } + ] + } + }, + { + "name": "PriceFeedMessage", + "repr": { + "kind": "c" + }, + "type": { + "kind": "struct", + "fields": [ + { + "name": "feed_id", + "docs": [ + "`FeedId` but avoid the type alias because of compatibility issues with Anchor's `idl-build` feature." + ], + "type": { + "array": [ + "u8", + 32 + ] + } + }, + { + "name": "price", + "type": "i64" + }, + { + "name": "conf", + "type": "u64" + }, + { + "name": "exponent", + "type": "i32" + }, + { + "name": "publish_time", + "docs": [ + "The timestamp of this price update in seconds" + ], + "type": "i64" + }, + { + "name": "prev_publish_time", + "docs": [ + "The timestamp of the previous price update. This field is intended to allow users to", + "identify the single unique price update for any moment in time:", + "for any time t, the unique update is the one such that prev_publish_time < t <= publish_time.", + "", + "Note that there may not be such an update while we are migrating to the new message-sending logic,", + "as some price updates on pythnet may not be sent to other chains (because the message-sending", + "logic may not have triggered). We can solve this problem by making the message-sending mandatory", + "(which we can do once publishers have migrated over).", + "", + "Additionally, this field may be equal to publish_time if the message is sent on a slot where", + "where the aggregation was unsuccesful. This problem will go away once all publishers have", + "migrated over to a recent version of pyth-agent." + ], + "type": "i64" + }, + { + "name": "ema_price", + "type": "i64" + }, + { + "name": "ema_conf", + "type": "u64" + } + ] + } + }, + { + "name": "PriceUpdateV2", + "docs": [ + "A price update account. This account is used by the Pyth Receiver program to store a verified price update from a Pyth price feed.", + "It contains:", + "- `write_authority`: The write authority for this account. This authority can close this account to reclaim rent or update the account to contain a different price update.", + "- `verification_level`: The [`VerificationLevel`] of this price update. This represents how many Wormhole guardian signatures have been verified for this price update.", + "- `price_message`: The actual price update.", + "- `posted_slot`: The slot at which this price update was posted." + ], + "type": { + "kind": "struct", + "fields": [ + { + "name": "write_authority", + "type": "pubkey" + }, + { + "name": "verification_level", + "type": { + "defined": { + "name": "VerificationLevel" + } + } + }, + { + "name": "price_message", + "type": { + "defined": { + "name": "PriceFeedMessage" + } + } + }, + { + "name": "posted_slot", + "type": "u64" + } + ] + } + }, + { + "name": "TokenRecoveredEvent", + "type": { + "kind": "struct", + "fields": [ + { + "name": "admin", + "type": "pubkey" + }, + { + "name": "amount", + "type": "u64" + } + ] + } + }, + { + "name": "VerificationLevel", + "docs": [ + "Pyth price updates are bridged to all blockchains via Wormhole.", + "Using the price updates on another chain requires verifying the signatures of the Wormhole guardians.", + "The usual process is to check the signatures for two thirds of the total number of guardians, but this can be cumbersome on Solana because of the transaction size limits,", + "so we also allow for partial verification.", + "", + "This enum represents how much a price update has been verified:", + "- If `Full`, we have verified the signatures for two thirds of the current guardians.", + "- If `Partial`, only `num_signatures` guardian signatures have been checked.", + "", + "# Warning", + "Using partially verified price updates is dangerous, as it lowers the threshold of guardians that need to collude to produce a malicious price update." + ], + "type": { + "kind": "enum", + "variants": [ + { + "name": "Partial", + "fields": [ + { + "name": "num_signatures", + "type": "u8" + } + ] + }, + { + "name": "Full" + } + ] + } + } + ] +} \ No newline at end of file diff --git a/e2e/solana-setup/type_pushsolanalocker.ts b/e2e/solana-setup/type_pushsolanalocker.ts new file mode 100644 index 00000000..e2bbb98e --- /dev/null +++ b/e2e/solana-setup/type_pushsolanalocker.ts @@ -0,0 +1,546 @@ +/** + * Program IDL in camelCase format in order to be used in JS/TS. + * + * Note that this is only a type helper and is not the actual IDL. The original + * IDL can be found at `target/idl/pushsolanalocker.json`. + */ +export type Pushsolanalocker = { + "address": "H2sHWWnihK2bdtJoM79G737FmzzLuJv5WC1ModcCDSE3", + "metadata": { + "name": "pushsolanalocker", + "version": "0.1.0", + "spec": "0.1.0", + "description": "Created with Anchor" + }, + "instructions": [ + { + "name": "addFunds", + "discriminator": [ + 132, + 237, + 76, + 57, + 80, + 10, + 179, + 138 + ], + "accounts": [ + { + "name": "locker", + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 108, + 111, + 99, + 107, + 101, + 114 + ] + } + ] + } + }, + { + "name": "vault", + "writable": true, + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 118, + 97, + 117, + 108, + 116 + ] + } + ] + } + }, + { + "name": "user", + "writable": true, + "signer": true + }, + { + "name": "priceUpdate" + }, + { + "name": "systemProgram", + "address": "11111111111111111111111111111111" + } + ], + "args": [ + { + "name": "amount", + "type": "u64" + }, + { + "name": "transactionHash", + "type": { + "array": [ + "u8", + 32 + ] + } + } + ] + }, + { + "name": "getSolPrice", + "discriminator": [ + 230, + 145, + 206, + 175, + 43, + 184, + 97, + 110 + ], + "accounts": [ + { + "name": "priceUpdate" + } + ], + "args": [], + "returns": { + "defined": { + "name": "priceData" + } + } + }, + { + "name": "initialize", + "discriminator": [ + 175, + 175, + 109, + 31, + 13, + 152, + 155, + 237 + ], + "accounts": [ + { + "name": "lockerData", + "writable": true, + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 108, + 111, + 99, + 107, + 101, + 114 + ] + } + ] + } + }, + { + "name": "vault", + "writable": true, + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 118, + 97, + 117, + 108, + 116 + ] + } + ] + } + }, + { + "name": "admin", + "writable": true, + "signer": true + }, + { + "name": "systemProgram", + "address": "11111111111111111111111111111111" + } + ], + "args": [] + }, + { + "name": "recoverTokens", + "discriminator": [ + 156, + 18, + 205, + 212, + 197, + 254, + 126, + 142 + ], + "accounts": [ + { + "name": "lockerData" + }, + { + "name": "vault", + "writable": true, + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 118, + 97, + 117, + 108, + 116 + ] + } + ] + } + }, + { + "name": "recipient", + "writable": true, + "signer": true + }, + { + "name": "admin", + "writable": true, + "signer": true + }, + { + "name": "systemProgram", + "address": "11111111111111111111111111111111" + } + ], + "args": [ + { + "name": "amount", + "type": "u64" + } + ] + } + ], + "accounts": [ + { + "name": "locker", + "discriminator": [ + 74, + 246, + 6, + 113, + 249, + 228, + 75, + 169 + ] + }, + { + "name": "priceUpdateV2", + "discriminator": [ + 34, + 241, + 35, + 99, + 157, + 126, + 244, + 205 + ] + } + ], + "events": [ + { + "name": "fundsAddedEvent", + "discriminator": [ + 127, + 31, + 108, + 255, + 187, + 19, + 70, + 68 + ] + }, + { + "name": "tokenRecoveredEvent", + "discriminator": [ + 72, + 100, + 110, + 181, + 188, + 125, + 10, + 53 + ] + } + ], + "errors": [ + { + "code": 6000, + "name": "noFundsSent", + "msg": "No SOL sent" + }, + { + "code": 6001, + "name": "unauthorized", + "msg": "unauthorized" + }, + { + "code": 6002, + "name": "invalidPrice", + "msg": "Invalid price data" + } + ], + "types": [ + { + "name": "fundsAddedEvent", + "type": { + "kind": "struct", + "fields": [ + { + "name": "user", + "type": "pubkey" + }, + { + "name": "solAmount", + "type": "u64" + }, + { + "name": "usdEquivalent", + "type": "i128" + }, + { + "name": "usdExponent", + "type": "i32" + }, + { + "name": "transactionHash", + "type": { + "array": [ + "u8", + 32 + ] + } + } + ] + } + }, + { + "name": "locker", + "type": { + "kind": "struct", + "fields": [ + { + "name": "admin", + "type": "pubkey" + }, + { + "name": "bump", + "type": "u8" + }, + { + "name": "vaultBump", + "type": "u8" + } + ] + } + }, + { + "name": "priceData", + "type": { + "kind": "struct", + "fields": [ + { + "name": "price", + "type": "i64" + }, + { + "name": "exponent", + "type": "i32" + }, + { + "name": "publishTime", + "type": "i64" + }, + { + "name": "confidence", + "type": "u64" + } + ] + } + }, + { + "name": "priceFeedMessage", + "repr": { + "kind": "c" + }, + "type": { + "kind": "struct", + "fields": [ + { + "name": "feedId", + "docs": [ + "`FeedId` but avoid the type alias because of compatibility issues with Anchor's `idl-build` feature." + ], + "type": { + "array": [ + "u8", + 32 + ] + } + }, + { + "name": "price", + "type": "i64" + }, + { + "name": "conf", + "type": "u64" + }, + { + "name": "exponent", + "type": "i32" + }, + { + "name": "publishTime", + "docs": [ + "The timestamp of this price update in seconds" + ], + "type": "i64" + }, + { + "name": "prevPublishTime", + "docs": [ + "The timestamp of the previous price update. This field is intended to allow users to", + "identify the single unique price update for any moment in time:", + "for any time t, the unique update is the one such that prev_publish_time < t <= publish_time.", + "", + "Note that there may not be such an update while we are migrating to the new message-sending logic,", + "as some price updates on pythnet may not be sent to other chains (because the message-sending", + "logic may not have triggered). We can solve this problem by making the message-sending mandatory", + "(which we can do once publishers have migrated over).", + "", + "Additionally, this field may be equal to publish_time if the message is sent on a slot where", + "where the aggregation was unsuccesful. This problem will go away once all publishers have", + "migrated over to a recent version of pyth-agent." + ], + "type": "i64" + }, + { + "name": "emaPrice", + "type": "i64" + }, + { + "name": "emaConf", + "type": "u64" + } + ] + } + }, + { + "name": "priceUpdateV2", + "docs": [ + "A price update account. This account is used by the Pyth Receiver program to store a verified price update from a Pyth price feed.", + "It contains:", + "- `write_authority`: The write authority for this account. This authority can close this account to reclaim rent or update the account to contain a different price update.", + "- `verification_level`: The [`VerificationLevel`] of this price update. This represents how many Wormhole guardian signatures have been verified for this price update.", + "- `price_message`: The actual price update.", + "- `posted_slot`: The slot at which this price update was posted." + ], + "type": { + "kind": "struct", + "fields": [ + { + "name": "writeAuthority", + "type": "pubkey" + }, + { + "name": "verificationLevel", + "type": { + "defined": { + "name": "verificationLevel" + } + } + }, + { + "name": "priceMessage", + "type": { + "defined": { + "name": "priceFeedMessage" + } + } + }, + { + "name": "postedSlot", + "type": "u64" + } + ] + } + }, + { + "name": "tokenRecoveredEvent", + "type": { + "kind": "struct", + "fields": [ + { + "name": "admin", + "type": "pubkey" + }, + { + "name": "amount", + "type": "u64" + } + ] + } + }, + { + "name": "verificationLevel", + "docs": [ + "Pyth price updates are bridged to all blockchains via Wormhole.", + "Using the price updates on another chain requires verifying the signatures of the Wormhole guardians.", + "The usual process is to check the signatures for two thirds of the total number of guardians, but this can be cumbersome on Solana because of the transaction size limits,", + "so we also allow for partial verification.", + "", + "This enum represents how much a price update has been verified:", + "- If `Full`, we have verified the signatures for two thirds of the current guardians.", + "- If `Partial`, only `num_signatures` guardian signatures have been checked.", + "", + "# Warning", + "Using partially verified price updates is dangerous, as it lowers the threshold of guardians that need to collude to produce a malicious price update." + ], + "type": { + "kind": "enum", + "variants": [ + { + "name": "partial", + "fields": [ + { + "name": "numSignatures", + "type": "u8" + } + ] + }, + { + "name": "full" + } + ] + } + } + ] +}; diff --git a/e2e/solana_localchain_chain_config.json b/e2e/solana_localchain_chain_config.json new file mode 100644 index 00000000..6a0957fc --- /dev/null +++ b/e2e/solana_localchain_chain_config.json @@ -0,0 +1,28 @@ +{ + "chain": "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1", + "public_rpc_url": "http://host.docker.internal:8899", + "vm_type": 2, + "gateway_address": "H2sHWWnihK2bdtJoM79G737FmzzLuJv5WC1ModcCDSE3", + "block_confirmation": { + "fast_inbound": 0, + "standard_inbound": 12 + }, + "gateway_methods": [ + { + "name": "add_funds", + "identifier": "84ed4c39500ab38a", + "event_identifier": "7f1f6cffbb134644", + "confirmation_type": 2 + }, + { + "name": "send_funds", + "identifier": "54f7d3283f6a0f3b", + "event_identifier": "2b1f1f0204ec6bff", + "confirmation_type": 1 + } + ], + "enabled": { + "isInboundEnabled": true, + "isOutboundEnabled": true + } +} diff --git a/scripts/test_node.sh b/scripts/test_node.sh index 50e1aa71..0c8f6544 100755 --- a/scripts/test_node.sh +++ b/scripts/test_node.sh @@ -171,4 +171,4 @@ sed -i -e 's/address = ":8080"/address = "0.0.0.0:'$ROSETTA'"/g' $HOME_DIR/confi # Faster blocks sed -i -e 's/timeout_commit = "5s"/timeout_commit = "'$BLOCK_TIME'"/g' $HOME_DIR/config/config.toml -BINARY start --pruning=nothing --minimum-gas-prices=1000000000$DENOM --rpc.laddr="tcp://0.0.0.0:$RPC" --json-rpc.api=eth,txpool,personal,net,debug,web3 --chain-id="$CHAIN_ID" +BINARY start --pruning=nothing --minimum-gas-prices=1000000000$DENOM --rpc.laddr="tcp://0.0.0.0:$RPC" --json-rpc.api=eth,txpool,personal,net,debug,web3 --chain-id="$CHAIN_ID" \ No newline at end of file diff --git a/scripts/test_node_e2e.sh b/scripts/test_node_e2e.sh new file mode 100644 index 00000000..1902e844 --- /dev/null +++ b/scripts/test_node_e2e.sh @@ -0,0 +1,176 @@ +#!/bin/bash +# Run this script to quickly install, setup, and run the current version of the network without docker. +# +# Examples: +# CHAIN_ID="localchain_9000-1" HOME_DIR="~/.pchain" BLOCK_TIME="1000ms" CLEAN=true sh scripts/test_node.sh +# CHAIN_ID="localchain_9000-2" HOME_DIR="~/.pchain" CLEAN=true RPC=36657 REST=2317 PROFF=6061 P2P=36656 GRPC=8090 GRPC_WEB=8091 ROSETTA=8081 BLOCK_TIME="500ms" sh scripts/test_node.sh +shopt -s expand_aliases +set -eu + +export KEY1="acc1" +export KEY2="acc2" +export KEY3="acc3" + +export CHAIN_ID=${CHAIN_ID:-"localchain_9000-1"} +export MONIKER=${MONIKER:-"localvalidator"} +export KEYALGO="eth_secp256k1" +export KEYRING=${KEYRING:-"test"} +export HOME_DIR=$(eval echo "${HOME_DIR:-"~/.pchain"}") +export BINARY=${BINARY:-pchaind} +export DENOM=${DENOM:-upc} + +export CLEAN=${CLEAN:-"false"} +export RPC=${RPC:-"26657"} +export REST=${REST:-"1317"} +export PROFF=${PROFF:-"6060"} +export P2P=${P2P:-"26656"} +export GRPC=${GRPC:-"9090"} +export GRPC_WEB=${GRPC_WEB:-"9091"} +export ROSETTA=${ROSETTA:-"8080"} +export BLOCK_TIME=${BLOCK_TIME:-"1s"} + +# if which binary does not exist, install it +# if [ -z `which $BINARY` ]; then +# make install + +# if [ -z `which $BINARY` ]; then +# echo "Ensure $BINARY is installed and in your PATH" +# exit 1 +# fi +# fi + +alias BINARY="$BINARY --home=$HOME_DIR" + +command -v $BINARY > /dev/null 2>&1 || { echo >&2 "$BINARY command not found. Ensure this is setup / properly installed in your GOPATH (make install)."; exit 1; } +command -v jq > /dev/null 2>&1 || { echo >&2 "jq not installed. More info: https://stedolan.github.io/jq/download/"; exit 1; } + +set_config() { + $BINARY config set client chain-id $CHAIN_ID + $BINARY config set client keyring-backend $KEYRING +} +set_config + + +from_scratch () { + # Fresh install on current branch + # make install + + # remove existing daemon files. + if [ ${#HOME_DIR} -le 2 ]; then + echo "HOME_DIR must be more than 2 characters long" + return + fi + rm -rf $HOME_DIR && echo "Removed $HOME_DIR" + + # reset values if not set already after whipe + set_config + + add_key() { + key=$1 + mnemonic=$2 + echo $mnemonic | BINARY keys add $key --keyring-backend $KEYRING --algo $KEYALGO --recover + } + + # push1ss5j8c8j453uecnczt3ms23lze30kxt4pzfvh9 + add_key $KEY1 "surface task term spring horse impact tortoise often session cable off catch harvest rain able jealous coral cargo portion surge spring genre mix avoid" + # push1j55s4vpvmncruakqhj2k2fywnc9mvsuhcap28q + add_key $KEY2 "season wing cost lunch leg absurd parent practice frost mistake choose leopard switch shrug wrist this pistol bright spike hurt fit meadow smart hazard" + # push1fgaewhyd9fkwtqaj9c233letwcuey6dgly9gv9 + add_key $KEY3 "episode silver life middle tumble slogan genius loop divide alpha raven bridge drive calm club system school raccoon unfold marine oyster radio treat sphere" + + BINARY init $MONIKER --chain-id $CHAIN_ID --default-denom $DENOM + + update_test_genesis () { + cat $HOME_DIR/config/genesis.json | jq "$1" > $HOME_DIR/config/tmp_genesis.json && mv $HOME_DIR/config/tmp_genesis.json $HOME_DIR/config/genesis.json + } + + # === CORE MODULES === + + # Block + update_test_genesis '.consensus_params["block"]["max_gas"]="100000000"' + + # Gov + update_test_genesis `printf '.app_state["gov"]["params"]["min_deposit"]=[{"denom":"%s","amount":"1000000"}]' $DENOM` + update_test_genesis '.app_state["gov"]["params"]["voting_period"]="30s"' + update_test_genesis '.app_state["gov"]["params"]["expedited_voting_period"]="15s"' + + update_test_genesis `printf '.app_state["evm"]["params"]["evm_denom"]="%s"' $DENOM` + update_test_genesis '.app_state["evm"]["params"]["active_static_precompiles"]=["0x00000000000000000000000000000000000000CB","0x00000000000000000000000000000000000000ca","0x0000000000000000000000000000000000000100","0x0000000000000000000000000000000000000400","0x0000000000000000000000000000000000000800","0x0000000000000000000000000000000000000801","0x0000000000000000000000000000000000000802","0x0000000000000000000000000000000000000803","0x0000000000000000000000000000000000000804","0x0000000000000000000000000000000000000805"]' + update_test_genesis '.app_state["erc20"]["params"]["native_precompiles"]=["0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE"]' # https://eips.ethereum.org/EIPS/eip-7528 + update_test_genesis `printf '.app_state["erc20"]["token_pairs"]=[{contract_owner:1,erc20_address:"0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE",denom:"%s",enabled:true}]' $DENOM` + update_test_genesis '.app_state["feemarket"]["params"]["no_base_fee"]=false' + update_test_genesis '.app_state["feemarket"]["params"]["base_fee"]="1000000000.000000000000000000"' + update_test_genesis '.app_state["feemarket"]["params"]["min_gas_price"]="1000000000.000000000000000000"' + + # staking + update_test_genesis `printf '.app_state["staking"]["params"]["bond_denom"]="%s"' $DENOM` + update_test_genesis '.app_state["staking"]["params"]["min_commission_rate"]="0.050000000000000000"' + + # mint + update_test_genesis `printf '.app_state["mint"]["params"]["mint_denom"]="%s"' $DENOM` + + # crisis + update_test_genesis `printf '.app_state["crisis"]["constant_fee"]={"denom":"%s","amount":"1000"}' $DENOM` + + ## abci + update_test_genesis '.consensus["params"]["abci"]["vote_extensions_enable_height"]="1"' + + # === CUSTOM MODULES === + # tokenfactory + update_test_genesis '.app_state["tokenfactory"]["params"]["denom_creation_fee"]=[]' + update_test_genesis '.app_state["tokenfactory"]["params"]["denom_creation_gas_consume"]=100000' + + # Allocate genesis accounts + # Total: 10 000000000 . 000000000 000000000 + BINARY genesis add-genesis-account $KEY1 5000000000000000000000000000$DENOM,100000000test --keyring-backend $KEYRING --append + BINARY genesis add-genesis-account $KEY2 3000000000000000000000000000$DENOM,90000000test --keyring-backend $KEYRING --append + BINARY genesis add-genesis-account $KEY3 2000000000000000000000000000$DENOM,90000000test --keyring-backend $KEYRING --append + + # Sign genesis transaction + # 10 000 . 000000000 000000000 + BINARY genesis gentx $KEY1 10000000000000000000000$DENOM --gas-prices 1000000000${DENOM} --keyring-backend $KEYRING --chain-id $CHAIN_ID + + BINARY genesis collect-gentxs + + BINARY genesis validate-genesis + err=$? + if [ $err -ne 0 ]; then + echo "Failed to validate genesis" + return + fi +} + +# check if CLEAN is not set to false +if [ "$CLEAN" != "false" ]; then + echo "Starting from a clean state" + from_scratch +fi + +echo "Starting node..." + +# Opens the RPC endpoint to outside connections +sed -i -e 's/laddr = "tcp:\/\/127.0.0.1:26657"/c\laddr = "tcp:\/\/0.0.0.0:'$RPC'"/g' $HOME_DIR/config/config.toml +sed -i -e 's/cors_allowed_origins = \[\]/cors_allowed_origins = \["\*"\]/g' $HOME_DIR/config/config.toml + +# REST endpoint +sed -i -e 's/address = "tcp:\/\/localhost:1317"/address = "tcp:\/\/0.0.0.0:'$REST'"/g' $HOME_DIR/config/app.toml +sed -i -e 's/enable = false/enable = true/g' $HOME_DIR/config/app.toml +sed -i -e 's/enabled-unsafe-cors = false/enabled-unsafe-cors = true/g' $HOME_DIR/config/app.toml + +# peer exchange +sed -i -e 's/pprof_laddr = "localhost:6060"/pprof_laddr = "localhost:'$PROFF'"/g' $HOME_DIR/config/config.toml +sed -i -e 's/laddr = "tcp:\/\/0.0.0.0:26656"/laddr = "tcp:\/\/0.0.0.0:'$P2P'"/g' $HOME_DIR/config/config.toml + +# GRPC +sed -i -e 's/address = "localhost:9090"/address = "0.0.0.0:'$GRPC'"/g' $HOME_DIR/config/app.toml +sed -i -e 's/address = "localhost:9091"/address = "0.0.0.0:'$GRPC_WEB'"/g' $HOME_DIR/config/app.toml + +# Rosetta Api +sed -i -e 's/address = ":8080"/address = "0.0.0.0:'$ROSETTA'"/g' $HOME_DIR/config/app.toml + +# Faster blocks +sed -i -e 's/timeout_commit = "5s"/timeout_commit = "'$BLOCK_TIME'"/g' $HOME_DIR/config/config.toml + +sed -i -e 's/address = "127.0.0.1:8545"/address = "0.0.0.0:8545"/g' $HOME_DIR/config/app.toml + +BINARY start --pruning=nothing --minimum-gas-prices=1000000000$DENOM --rpc.laddr="tcp://0.0.0.0:$RPC" --json-rpc.address="0.0.0.0:8545" --json-rpc.api=eth,txpool,personal,net,debug,web3 --chain-id="$CHAIN_ID" diff --git a/x/uregistry/types/params.go b/x/uregistry/types/params.go index 548788eb..dc56afee 100755 --- a/x/uregistry/types/params.go +++ b/x/uregistry/types/params.go @@ -8,7 +8,7 @@ import ( func DefaultParams() Params { // TODO: return Params{ - Admin: "push1negskcfqu09j5zvpk7nhvacnwyy2mafffy7r6a", + Admin: "push1gjaw568e35hjc8udhat0xnsxxmkm2snrexxz20", } }