Skip to content

Commit

Permalink
feat(solana): js sdk (#1307)
Browse files Browse the repository at this point in the history
* Do it

* Remove some duplicate code

* Cleanup

* Cleanup

* Cleanup import

* Correct description

* Fix path

* Cleanup deps

* Unique

* Works

* Continue

* Lint

* Lint config

* Fix ci

* Checkpoint

* Checkpoint

* Gitignore

* Cleanup

* Cleanup

* Continue building the sdk

* build function

* Remove files

* Remove files

* Rename

* Refactor : make transaction builder

* Make commitment

* Move

* Progress

* Checkpoint

* Ephemeral signers 2

* Checkpoint

* Checkpoint

* Fix bug

* Cleanup idls

* Compute units

* Make program addresses configurable

* Handle arrays

* Handle arrays

* Move PythSolanaReceiver

* Cleanup constants

* Contants

* Refactor constants

* Gitignore refactor

* package lock

* Cleanup idl

* Add useful static

* Add useful static

* Add useful static

* Lint

* Add lint config
  • Loading branch information
guibescos authored Feb 28, 2024
1 parent 3835042 commit e986b69
Show file tree
Hide file tree
Showing 28 changed files with 5,682 additions and 396 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/ci-solana-contract.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,4 @@ jobs:
- name: Run tests
run: cargo-test-sbf
- name: Run sdk tests
run: cargo test --p pyth-solana-sdk
run: cargo test --package pyth-solana-receiver-state
3 changes: 2 additions & 1 deletion governance/xc_admin/packages/xc_admin_common/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@
"bigint-buffer": "^1.1.5",
"ethers": "^5.7.2",
"lodash": "^4.17.21",
"typescript": "^4.9.4"
"typescript": "^4.9.4",
"@pythnetwork/solana-utils": "*"
},
"devDependencies": {
"@types/bn.js": "^5.1.1",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,19 +15,13 @@ import {
} from "@solana/web3.js";
import {
batchIntoExecutorPayload,
batchIntoTransactions,
getSizeOfCompressedU16,
getSizeOfExecutorInstructions,
getSizeOfTransaction,
MAX_EXECUTOR_PAYLOAD_SIZE,
} from "..";

it("Unit test compressed u16 size", async () => {
expect(getSizeOfCompressedU16(127)).toBe(1);
expect(getSizeOfCompressedU16(128)).toBe(2);
expect(getSizeOfCompressedU16(16383)).toBe(2);
expect(getSizeOfCompressedU16(16384)).toBe(3);
});
import {
getSizeOfTransaction,
TransactionBuilder,
} from "@pythnetwork/solana-utils";

it("Unit test for getSizeOfTransaction", async () => {
jest.setTimeout(60000);
Expand Down Expand Up @@ -84,7 +78,7 @@ it("Unit test for getSizeOfTransaction", async () => {
transaction.recentBlockhash = "GqdFtdM7zzWw33YyHtBNwPhyBsdYKcfm9gT47bWnbHvs"; // Mock blockhash from devnet
transaction.feePayer = payer.publicKey;
expect(transaction.serialize({ requireAllSignatures: false }).length).toBe(
getSizeOfTransaction(ixsToSend)
getSizeOfTransaction(ixsToSend, false)
);
});

Expand Down Expand Up @@ -115,21 +109,22 @@ it("Unit test for getSizeOfTransaction", async () => {
);
}

const txToSend: Transaction[] = batchIntoTransactions(ixsToSend);
const txToSend: Transaction[] =
TransactionBuilder.batchIntoLegacyTransactions(ixsToSend);
expect(
txToSend.map((tx) => tx.instructions.length).reduce((a, b) => a + b)
).toBe(ixsToSend.length);
expect(
txToSend.every(
(tx) => getSizeOfTransaction(tx.instructions) <= PACKET_DATA_SIZE
(tx) => getSizeOfTransaction(tx.instructions, false) <= PACKET_DATA_SIZE
)
).toBeTruthy();

for (let tx of txToSend) {
tx.recentBlockhash = "GqdFtdM7zzWw33YyHtBNwPhyBsdYKcfm9gT47bWnbHvs"; // Mock blockhash from devnet
tx.feePayer = payer.publicKey;
expect(tx.serialize({ requireAllSignatures: false }).length).toBe(
getSizeOfTransaction(tx.instructions)
getSizeOfTransaction(tx.instructions, false)
);
}

Expand Down
79 changes: 3 additions & 76 deletions governance/xc_admin/packages/xc_admin_common/src/propose.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import SquadsMesh, { getIxAuthorityPDA, getTxPDA } from "@sqds/mesh";
import { MultisigAccount } from "@sqds/mesh/lib/types";
import { mapKey } from "./remote_executor";
import { WORMHOLE_ADDRESS } from "./wormhole";
import { TransactionBuilder } from "@pythnetwork/solana-utils";

export const MAX_EXECUTOR_PAYLOAD_SIZE = PACKET_DATA_SIZE - 687; // Bigger payloads won't fit in one addInstruction call when adding to the proposal
export const MAX_INSTRUCTIONS_PER_PROPOSAL = 256 - 1;
Expand Down Expand Up @@ -256,7 +257,7 @@ export class MultisigVault {
ixToSend.push(await this.activateProposalIx(proposalAddress));
ixToSend.push(await this.approveProposalIx(proposalAddress));

const txToSend = batchIntoTransactions(ixToSend);
const txToSend = TransactionBuilder.batchIntoLegacyTransactions(ixToSend);
await this.sendAllTransactions(txToSend);
return proposalAddress;
}
Expand Down Expand Up @@ -360,7 +361,7 @@ export class MultisigVault {
}
}

const txToSend = batchIntoTransactions(ixToSend);
const txToSend = TransactionBuilder.batchIntoLegacyTransactions(ixToSend);

await this.sendAllTransactions(txToSend);
return newProposals;
Expand Down Expand Up @@ -445,32 +446,6 @@ export function batchIntoExecutorPayload(
return batches;
}

/**
* Batch instructions into transactions
*/
export function batchIntoTransactions(
instructions: TransactionInstruction[]
): Transaction[] {
let i = 0;
const txToSend: Transaction[] = [];
while (i < instructions.length) {
let j = i + 2;
while (
j < instructions.length &&
getSizeOfTransaction(instructions.slice(i, j)) <= PACKET_DATA_SIZE
) {
j += 1;
}
const tx = new Transaction();
for (let k = i; k < j - 1; k += 1) {
tx.add(instructions[k]);
}
i = j - 1;
txToSend.push(tx);
}
return txToSend;
}

/** Get the size of instructions when serialized as in a remote executor payload */
export function getSizeOfExecutorInstructions(
instructions: TransactionInstruction[]
Expand All @@ -481,54 +456,6 @@ export function getSizeOfExecutorInstructions(
})
.reduce((a, b) => a + b);
}
/**
* Get the size of a transaction that would contain the provided array of instructions
*/
export function getSizeOfTransaction(
instructions: TransactionInstruction[]
): number {
const signers = new Set<string>();
const accounts = new Set<string>();

instructions.map((ix) => {
accounts.add(ix.programId.toBase58()),
ix.keys.map((key) => {
if (key.isSigner) {
signers.add(key.pubkey.toBase58());
}
accounts.add(key.pubkey.toBase58());
});
});

const instruction_sizes: number = instructions
.map(
(ix) =>
1 +
getSizeOfCompressedU16(ix.keys.length) +
ix.keys.length +
getSizeOfCompressedU16(ix.data.length) +
ix.data.length
)
.reduce((a, b) => a + b, 0);

return (
1 +
signers.size * 64 +
3 +
getSizeOfCompressedU16(accounts.size) +
32 * accounts.size +
32 +
getSizeOfCompressedU16(instructions.length) +
instruction_sizes
);
}

/**
* Get the size of n in bytes when serialized as a CompressedU16
*/
export function getSizeOfCompressedU16(n: number) {
return 1 + Number(n >= 128) + Number(n >= 16384);
}

/**
* Wrap `instruction` in a Wormhole message for remote execution
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,9 +74,11 @@ const usePyth = (): PythHookData => {
connectionRef.current = connection
;(async () => {
try {
const allPythAccounts = await connection.getProgramAccounts(
getPythProgramKeyForCluster(cluster)
)
const allPythAccounts = [
...(await connection.getProgramAccounts(
getPythProgramKeyForCluster(cluster)
)),
]
if (cancelled) return
const priceRawConfigs: { [key: string]: PriceRawConfig } = {}

Expand Down
Loading

0 comments on commit e986b69

Please sign in to comment.