Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: wormhole-foundation/native-token-transfers
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: main
Choose a base ref
...
head repository: wormhole-foundation/native-token-transfers
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: solana/ts-tests-verify-ci
Choose a head ref
Can’t automatically merge. Don’t worry, you can still create the pull request.
  • 11 commits
  • 9 files changed
  • 1 contributor

Commits on Jul 23, 2024

  1. Copy the full SHA
    bb05baa View commit details
  2. Copy the full SHA
    7d7c6c1 View commit details
  3. solana: Add testcase to check burning and locking mode for transfer f…

    …ee token
    nvsriram committed Jul 23, 2024
    Copy the full SHA
    aad3e9b View commit details
  4. Copy the full SHA
    ba99c96 View commit details
  5. Copy the full SHA
    dcc4630 View commit details
  6. solana: Update Makefile to execute run-tests script for testing

    nvsriram committed Jul 23, 2024
    Copy the full SHA
    d90e66c View commit details
  7. solana: Update Solana CI/ Anchor test to execute run-tests script

    nvsriram committed Jul 23, 2024
    Copy the full SHA
    7f69dbb View commit details
  8. solana: Check that CI fails on faulty push

    nvsriram committed Jul 23, 2024
    Copy the full SHA
    0dbd46c View commit details

Commits on Jul 24, 2024

  1. solana: Ensure Solana CI/ Anchor test succeeds to fix

    nvsriram committed Jul 24, 2024
    Copy the full SHA
    ac15701 View commit details

Commits on Jul 29, 2024

  1. solana: Update script to pkill any running solana-test-validators

    nvsriram committed Jul 29, 2024
    Copy the full SHA
    05d8ce5 View commit details
  2. solana: Update script to kill rpc and faucet ports

    nvsriram committed Jul 29, 2024
    Copy the full SHA
    087d3d0 View commit details
2 changes: 1 addition & 1 deletion .github/workflows/solana.yml
Original file line number Diff line number Diff line change
@@ -146,5 +146,5 @@ jobs:
run: |
git diff --exit-code ts/idl
- name: Run tests
run: anchor test --skip-build
run: ./run-tests
shell: bash
2 changes: 1 addition & 1 deletion solana/Makefile
Original file line number Diff line number Diff line change
@@ -17,7 +17,7 @@ build:


test: idl sdk node_modules
anchor test --skip-build
./run-tests

idl: build
@echo "IDL Version: $(VERSION)"
2 changes: 1 addition & 1 deletion solana/package.json
Original file line number Diff line number Diff line change
@@ -38,7 +38,7 @@
"build": "npm run build:esm && npm run build:cjs",
"rebuild": "npm run clean && npm run build",
"clean": "rm -rf ./dist",
"test:ci": "jest --config ./jest.config.ts",
"test:ci": "jest --config ./jest.config.ts --detectOpenHandles",
"build:contracts": "make build"
},
"devDependencies": {
22 changes: 22 additions & 0 deletions solana/run-tests
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#!/usr/bin/env bash

set -euo pipefail

RPC_PORT_NUMBER=8899
FAUCET_PORT_NUMBER=9900

# Run each tests/*.test.ts file separately to avoid account state persisting between tests
for file in `ls tests/*.test.ts`
do
# convert file-name to FILE_NAME
filename=$(basename -- "$file")
filename="${filename%.test.*}"
env_flag="$(tr '[:lower:]' '[:upper:]' <<< ${filename//-/_})"

env $env_flag=1 bash -c 'anchor test --skip-build'

# kill solana validator if still running to avoid port already in use error
if pgrep solana-test-validator; then pkill solana-test-validator; fi
lsof -i tcp:${RPC_PORT_NUMBER} | awk 'NR!=1 {print $2}' | xargs kill
lsof -i tcp:${FAUCET_PORT_NUMBER} | awk 'NR!=1 {print $2}' | xargs kill
done
232 changes: 232 additions & 0 deletions solana/tests/transfer-fee-burning.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,232 @@
import * as anchor from "@coral-xyz/anchor";
import * as spl from "@solana/spl-token";
import {
SystemProgram,
Transaction,
sendAndConfirmTransaction,
} from "@solana/web3.js";
import {
AccountAddress,
ChainAddress,
ChainContext,
Signer,
UniversalAddress,
Wormhole,
contracts,
encoding,
} from "@wormhole-foundation/sdk";
import * as testing from "@wormhole-foundation/sdk-definitions/testing";
import {
SolanaPlatform,
getSolanaSignAndSendSigner,
} from "@wormhole-foundation/sdk-solana";
import * as fs from "fs";
import { SolanaNtt } from "../ts/sdk/index.js";
import { handleTestSkip, signSendWait } from "./utils/index.js";

handleTestSkip(__filename);

const solanaRootDir = `${__dirname}/../`;

const CORE_BRIDGE_ADDRESS = contracts.coreBridge("Mainnet", "Solana");
const NTT_ADDRESS = anchor.workspace.ExampleNativeTokenTransfers.programId;

const w = new Wormhole("Devnet", [SolanaPlatform], {
chains: { Solana: { contracts: { coreBridge: CORE_BRIDGE_ADDRESS } } },
});

const remoteXcvr: ChainAddress = {
chain: "Ethereum",
address: new UniversalAddress(
encoding.bytes.encode("transceiver".padStart(32, "\0"))
),
};
const remoteMgr: ChainAddress = {
chain: "Ethereum",
address: new UniversalAddress(
encoding.bytes.encode("nttManager".padStart(32, "\0"))
),
};

const receiver = testing.utils.makeUniversalChainAddress("Ethereum");

const payerSecretKey = Uint8Array.from(
JSON.parse(
fs.readFileSync(`${solanaRootDir}/keys/test.json`, {
encoding: "utf-8",
})
)
);
const payer = anchor.web3.Keypair.fromSecretKey(payerSecretKey);

const connection = new anchor.web3.Connection(
"http://localhost:8899",
"confirmed"
);

// make sure we're using the exact same Connection obj for rpc
const ctx: ChainContext<"Devnet", "Solana"> = w
.getPlatform("Solana")
.getChain("Solana", connection);

const mintAuthority = anchor.web3.Keypair.generate();
const mintKeypair = anchor.web3.Keypair.generate();
const mint = mintKeypair.publicKey;
const transferFeeConfigAuthority = anchor.web3.Keypair.generate();
const withdrawWithheldAuthority = anchor.web3.Keypair.generate();
const decimals = 9;
const feeBasisPoints = 50;
const maxFee = BigInt(5_000);
const mintAmount = BigInt(1_000_000_000);

const transferAmount = 100_000n;

let signer: Signer;
let sender: AccountAddress<"Solana">;
let ntt: SolanaNtt<"Devnet", "Solana">;
let tokenAccount: anchor.web3.PublicKey;
let tokenAddress: string;

const TOKEN_PROGRAM = spl.TOKEN_2022_PROGRAM_ID;

describe("example-native-token-transfers", () => {
describe("Transfer Fee Burning", () => {
beforeAll(async () => {
try {
signer = await getSolanaSignAndSendSigner(connection, payer, {
//debug: true,
});
sender = Wormhole.parseAddress("Solana", signer.address());

// initialize mint
const extensions = [spl.ExtensionType.TransferFeeConfig];
const mintLen = spl.getMintLen(extensions);
const lamports = await connection.getMinimumBalanceForRentExemption(
mintLen
);
const transaction = new Transaction().add(
SystemProgram.createAccount({
fromPubkey: payer.publicKey,
newAccountPubkey: mint,
space: mintLen,
lamports,
programId: TOKEN_PROGRAM,
}),
spl.createInitializeTransferFeeConfigInstruction(
mint,
transferFeeConfigAuthority.publicKey,
withdrawWithheldAuthority.publicKey,
feeBasisPoints,
maxFee,
TOKEN_PROGRAM
),
spl.createInitializeMintInstruction(
mint,
decimals,
mintAuthority.publicKey,
null,
TOKEN_PROGRAM
)
);
await sendAndConfirmTransaction(
connection,
transaction,
[payer, mintKeypair],
undefined
);

// create and fund token account
tokenAccount = await spl.createAccount(
connection,
payer,
mint,
payer.publicKey,
undefined,
undefined,
TOKEN_PROGRAM
);
await spl.mintTo(
connection,
payer,
mint,
tokenAccount,
mintAuthority,
mintAmount,
[],
undefined,
TOKEN_PROGRAM
);

// create our contract client
tokenAddress = mint.toBase58();
ntt = new SolanaNtt("Devnet", "Solana", connection, {
...ctx.config.contracts,
ntt: {
token: tokenAddress,
manager: NTT_ADDRESS,
transceiver: { wormhole: NTT_ADDRESS },
},
});

// transfer mint authority to ntt
await spl.setAuthority(
connection,
payer,
mint,
mintAuthority,
spl.AuthorityType.MintTokens,
ntt.pdas.tokenAuthority(),
[],
undefined,
TOKEN_PROGRAM
);

// init
const initTxs = ntt.initialize(sender, {
mint,
outboundLimit: 100_000_000n,
mode: "burning",
});
await signSendWait(ctx, initTxs, signer);

// register
const registerTxs = ntt.registerTransceiver({
payer,
owner: payer,
transceiver: ntt.program.programId,
});
await signSendWait(ctx, registerTxs, signer);

// set Wormhole xcvr peer
const setXcvrPeerTxs = ntt.setWormholeTransceiverPeer(
remoteXcvr,
sender
);
await signSendWait(ctx, setXcvrPeerTxs, signer);

// set manager peer
const setPeerTxs = ntt.setPeer(remoteMgr, 18, 10_000_000n, sender);
await signSendWait(ctx, setPeerTxs, signer);
} catch (e) {
console.error("Failed to setup peer: ", e);
throw e;
}
});

it("Returns with error", async () => {
// TODO: keep or remove the `outboxItem` param?
// added as a way to keep tests the same but it technically breaks the Ntt interface
const outboxItem = anchor.web3.Keypair.generate();
const xferTxs = ntt.transfer(
sender,
transferAmount,
receiver,
{ queue: false, automatic: false, gasDropoff: 0n },
outboxItem
);
await expect(
signSendWait(ctx, xferTxs, signer, false, true)
).rejects.toThrow();
});
});
});
Loading