parent
8ef49e6128
commit
31ab162168
|
@ -3748,9 +3748,9 @@
|
|||
"license": "BSD-3-Clause"
|
||||
},
|
||||
"node_modules/@pythnetwork/client": {
|
||||
"version": "2.9.0",
|
||||
"resolved": "https://registry.npmjs.org/@pythnetwork/client/-/client-2.9.0.tgz",
|
||||
"integrity": "sha512-2CyDmTwPWW+JCQgRKUpwMR/31oiLWH6I3GA0h2ZXIcbt/hWxcr5TXyKlWuyi+l+jh73WWh88gq8NXLoIgRcvkA==",
|
||||
"version": "2.10.0",
|
||||
"resolved": "https://registry.npmjs.org/@pythnetwork/client/-/client-2.10.0.tgz",
|
||||
"integrity": "sha512-dmj8dAj8K7rhSpaDUIjLGKYs+64kM1LR/V1ht/IShg6Zu0GNJY522+0K0EBcmbjzs3GaHua873DlcvQJlU5iHw==",
|
||||
"dependencies": {
|
||||
"buffer": "^6.0.1"
|
||||
},
|
||||
|
@ -12759,7 +12759,7 @@
|
|||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@certusone/wormhole-sdk": "^0.9.8",
|
||||
"@pythnetwork/client": "^2.9.0",
|
||||
"@pythnetwork/client": "^2.10.0",
|
||||
"@solana/buffer-layout": "^4.0.1",
|
||||
"@solana/web3.js": "^1.73.0",
|
||||
"@sqds/mesh": "^1.0.6",
|
||||
|
@ -15331,9 +15331,9 @@
|
|||
"version": "1.1.0"
|
||||
},
|
||||
"@pythnetwork/client": {
|
||||
"version": "2.9.0",
|
||||
"resolved": "https://registry.npmjs.org/@pythnetwork/client/-/client-2.9.0.tgz",
|
||||
"integrity": "sha512-2CyDmTwPWW+JCQgRKUpwMR/31oiLWH6I3GA0h2ZXIcbt/hWxcr5TXyKlWuyi+l+jh73WWh88gq8NXLoIgRcvkA==",
|
||||
"version": "2.10.0",
|
||||
"resolved": "https://registry.npmjs.org/@pythnetwork/client/-/client-2.10.0.tgz",
|
||||
"integrity": "sha512-dmj8dAj8K7rhSpaDUIjLGKYs+64kM1LR/V1ht/IShg6Zu0GNJY522+0K0EBcmbjzs3GaHua873DlcvQJlU5iHw==",
|
||||
"requires": {
|
||||
"buffer": "^6.0.1"
|
||||
},
|
||||
|
@ -21192,7 +21192,7 @@
|
|||
"version": "file:packages/xc-admin-common",
|
||||
"requires": {
|
||||
"@certusone/wormhole-sdk": "^0.9.8",
|
||||
"@pythnetwork/client": "*",
|
||||
"@pythnetwork/client": "^2.10.0",
|
||||
"@solana/buffer-layout": "^4.0.1",
|
||||
"@solana/web3.js": "^1.73.0",
|
||||
"@sqds/mesh": "^1.0.6",
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"@certusone/wormhole-sdk": "^0.9.8",
|
||||
"@pythnetwork/client": "^2.9.0",
|
||||
"@pythnetwork/client": "^2.10.0",
|
||||
"@solana/buffer-layout": "^4.0.1",
|
||||
"@solana/web3.js": "^1.73.0",
|
||||
"@sqds/mesh": "^1.0.6",
|
||||
|
|
|
@ -0,0 +1,167 @@
|
|||
import { AnchorProvider, Wallet } from "@project-serum/anchor";
|
||||
import { pythOracleProgram } from "@pythnetwork/client";
|
||||
import {
|
||||
getPythClusterApiUrl,
|
||||
getPythProgramKeyForCluster,
|
||||
PythCluster,
|
||||
} from "@pythnetwork/client/lib/cluster";
|
||||
import { Connection, Keypair, PublicKey } from "@solana/web3.js";
|
||||
import { MultisigInstructionProgram, MultisigParser } from "..";
|
||||
import { PythMultisigInstruction } from "../multisig_transaction/PythMultisigInstruction";
|
||||
|
||||
test("Pyth multisig instruction parse: create price account", (done) => {
|
||||
jest.setTimeout(60000);
|
||||
|
||||
const cluster: PythCluster = "devnet";
|
||||
const pythProgram = pythOracleProgram(
|
||||
getPythProgramKeyForCluster(cluster),
|
||||
new AnchorProvider(
|
||||
new Connection(getPythClusterApiUrl(cluster)),
|
||||
new Wallet(new Keypair()),
|
||||
AnchorProvider.defaultOptions()
|
||||
)
|
||||
);
|
||||
const parser = MultisigParser.fromCluster(cluster);
|
||||
|
||||
pythProgram.methods
|
||||
.addPrice(-8, 1)
|
||||
.accounts({
|
||||
fundingAccount: PublicKey.unique(),
|
||||
productAccount: PublicKey.unique(),
|
||||
priceAccount: PublicKey.unique(),
|
||||
})
|
||||
.instruction()
|
||||
.then((instruction) => {
|
||||
const parsedInstruction = parser.parseInstruction(instruction);
|
||||
|
||||
if (parsedInstruction instanceof PythMultisigInstruction) {
|
||||
expect(parsedInstruction.program).toBe(
|
||||
MultisigInstructionProgram.PythOracle
|
||||
);
|
||||
expect(parsedInstruction.name).toBe("addPrice");
|
||||
expect(
|
||||
parsedInstruction.accounts.named["fundingAccount"].pubkey.equals(
|
||||
instruction.keys[0].pubkey
|
||||
)
|
||||
).toBeTruthy();
|
||||
expect(
|
||||
parsedInstruction.accounts.named["fundingAccount"].isSigner
|
||||
).toBe(instruction.keys[0].isSigner);
|
||||
expect(
|
||||
parsedInstruction.accounts.named["fundingAccount"].isWritable
|
||||
).toBe(instruction.keys[0].isWritable);
|
||||
console.log(parsedInstruction.accounts.named["productAccount"]);
|
||||
expect(
|
||||
parsedInstruction.accounts.named["productAccount"].pubkey.equals(
|
||||
instruction.keys[1].pubkey
|
||||
)
|
||||
).toBeTruthy();
|
||||
expect(
|
||||
parsedInstruction.accounts.named["productAccount"].isSigner
|
||||
).toBe(instruction.keys[1].isSigner);
|
||||
expect(
|
||||
parsedInstruction.accounts.named["productAccount"].isWritable
|
||||
).toBe(instruction.keys[1].isWritable);
|
||||
expect(
|
||||
parsedInstruction.accounts.named["priceAccount"].pubkey.equals(
|
||||
instruction.keys[2].pubkey
|
||||
)
|
||||
).toBeTruthy();
|
||||
expect(parsedInstruction.accounts.named["priceAccount"].isSigner).toBe(
|
||||
instruction.keys[2].isSigner
|
||||
);
|
||||
expect(
|
||||
parsedInstruction.accounts.named["priceAccount"].isWritable
|
||||
).toBe(instruction.keys[2].isWritable);
|
||||
expect(
|
||||
parsedInstruction.accounts.named["permissionsAccount"].pubkey.equals(
|
||||
instruction.keys[3].pubkey
|
||||
)
|
||||
).toBeTruthy();
|
||||
expect(
|
||||
parsedInstruction.accounts.named["permissionsAccount"].isSigner
|
||||
).toBe(instruction.keys[3].isSigner);
|
||||
expect(
|
||||
parsedInstruction.accounts.named["permissionsAccount"].isWritable
|
||||
).toBe(instruction.keys[3].isWritable);
|
||||
expect(parsedInstruction.accounts.remaining.length).toBe(0);
|
||||
|
||||
expect(parsedInstruction.args.expo).toBe(-8);
|
||||
expect(parsedInstruction.args.pType).toBe(1);
|
||||
done();
|
||||
} else {
|
||||
done("Not instance of PythMultisigInstruction");
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
test("Pyth multisig instruction parse: set minimum publishers", (done) => {
|
||||
jest.setTimeout(60000);
|
||||
|
||||
const cluster: PythCluster = "devnet";
|
||||
const pythProgram = pythOracleProgram(
|
||||
getPythProgramKeyForCluster(cluster),
|
||||
new AnchorProvider(
|
||||
new Connection(getPythClusterApiUrl(cluster)),
|
||||
new Wallet(new Keypair()),
|
||||
AnchorProvider.defaultOptions()
|
||||
)
|
||||
);
|
||||
const parser = MultisigParser.fromCluster(cluster);
|
||||
|
||||
pythProgram.methods
|
||||
.setMinPub(25, [0, 0, 0])
|
||||
.accounts({
|
||||
fundingAccount: PublicKey.unique(),
|
||||
priceAccount: PublicKey.unique(),
|
||||
})
|
||||
.instruction()
|
||||
.then((instruction) => {
|
||||
const parsedInstruction = parser.parseInstruction(instruction);
|
||||
|
||||
if (parsedInstruction instanceof PythMultisigInstruction) {
|
||||
expect(parsedInstruction.program).toBe(
|
||||
MultisigInstructionProgram.PythOracle
|
||||
);
|
||||
expect(parsedInstruction.name).toBe("setMinPub");
|
||||
expect(
|
||||
parsedInstruction.accounts.named["fundingAccount"].pubkey.equals(
|
||||
instruction.keys[0].pubkey
|
||||
)
|
||||
).toBeTruthy();
|
||||
expect(
|
||||
parsedInstruction.accounts.named["fundingAccount"].isSigner
|
||||
).toBe(instruction.keys[0].isSigner);
|
||||
expect(
|
||||
parsedInstruction.accounts.named["fundingAccount"].isWritable
|
||||
).toBe(instruction.keys[0].isWritable);
|
||||
expect(
|
||||
parsedInstruction.accounts.named["priceAccount"].pubkey.equals(
|
||||
instruction.keys[1].pubkey
|
||||
)
|
||||
).toBeTruthy();
|
||||
expect(parsedInstruction.accounts.named["priceAccount"].isSigner).toBe(
|
||||
instruction.keys[1].isSigner
|
||||
);
|
||||
expect(
|
||||
parsedInstruction.accounts.named["priceAccount"].isWritable
|
||||
).toBe(instruction.keys[1].isWritable);
|
||||
expect(
|
||||
parsedInstruction.accounts.named["permissionsAccount"].pubkey.equals(
|
||||
instruction.keys[2].pubkey
|
||||
)
|
||||
).toBeTruthy();
|
||||
expect(
|
||||
parsedInstruction.accounts.named["permissionsAccount"].isSigner
|
||||
).toBe(instruction.keys[2].isSigner);
|
||||
expect(
|
||||
parsedInstruction.accounts.named["permissionsAccount"].isWritable
|
||||
).toBe(instruction.keys[2].isWritable);
|
||||
expect(parsedInstruction.accounts.remaining.length).toBe(0);
|
||||
expect(parsedInstruction.args.minPub).toBe(25);
|
||||
done();
|
||||
} else {
|
||||
done("Not instance of PythMultisigInstruction");
|
||||
}
|
||||
});
|
||||
});
|
|
@ -46,9 +46,6 @@ test("Wormhole multisig instruction parse: send message without governance paylo
|
|||
.instruction()
|
||||
.then((instruction) => {
|
||||
const parsedInstruction = parser.parseInstruction(instruction);
|
||||
expect(
|
||||
parsedInstruction instanceof WormholeMultisigInstruction
|
||||
).toBeTruthy();
|
||||
if (parsedInstruction instanceof WormholeMultisigInstruction) {
|
||||
expect(parsedInstruction.program).toBe(
|
||||
MultisigInstructionProgram.WormholeBridge
|
||||
|
@ -161,7 +158,7 @@ test("Wormhole multisig instruction parse: send message without governance paylo
|
|||
expect(parsedInstruction.args.targetChain).toBeUndefined();
|
||||
done();
|
||||
} else {
|
||||
done("Not instance of WormholeInstruction");
|
||||
done("Not instance of WormholeMultisigInstruction");
|
||||
}
|
||||
});
|
||||
});
|
||||
|
@ -354,7 +351,7 @@ test("Wormhole multisig instruction parse: send message with governance payload"
|
|||
done("Not instance of ExecutePostedVaa");
|
||||
}
|
||||
} else {
|
||||
done("Not instance of WormholeInstruction");
|
||||
done("Not instance of WormholeMultisigInstruction");
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
import { MultisigInstruction, MultisigInstructionProgram } from ".";
|
||||
import { AnchorAccounts, resolveAccountNames } from "./anchor";
|
||||
import { pythIdl, pythOracleCoder } from "@pythnetwork/client";
|
||||
import { TransactionInstruction } from "@solana/web3.js";
|
||||
import { Idl } from "@coral-xyz/anchor";
|
||||
|
||||
export class PythMultisigInstruction implements MultisigInstruction {
|
||||
readonly program = MultisigInstructionProgram.PythOracle;
|
||||
readonly name: string;
|
||||
readonly args: { [key: string]: any };
|
||||
readonly accounts: AnchorAccounts;
|
||||
|
||||
constructor(
|
||||
name: string,
|
||||
args: { [key: string]: any },
|
||||
accounts: AnchorAccounts
|
||||
) {
|
||||
this.name = name;
|
||||
this.args = args;
|
||||
this.accounts = accounts;
|
||||
}
|
||||
|
||||
static fromTransactionInstruction(
|
||||
instruction: TransactionInstruction
|
||||
): PythMultisigInstruction {
|
||||
const pythInstructionCoder = pythOracleCoder().instruction;
|
||||
|
||||
const deserializedData = pythInstructionCoder.decode(instruction.data);
|
||||
|
||||
if (deserializedData) {
|
||||
return new PythMultisigInstruction(
|
||||
deserializedData.name,
|
||||
deserializedData.data,
|
||||
resolveAccountNames(pythIdl as Idl, deserializedData.name, instruction)
|
||||
);
|
||||
} else {
|
||||
return new PythMultisigInstruction(
|
||||
"Unrecognized instruction",
|
||||
{},
|
||||
{ named: {}, remaining: instruction.keys }
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,6 +4,7 @@ import {
|
|||
} from "@pythnetwork/client/lib/cluster";
|
||||
import { PublicKey, TransactionInstruction } from "@solana/web3.js";
|
||||
import { WORMHOLE_ADDRESS } from "../wormhole";
|
||||
import { PythMultisigInstruction } from "./PythMultisigInstruction";
|
||||
import { WormholeMultisigInstruction } from "./WormholeMultisigInstruction";
|
||||
|
||||
export enum MultisigInstructionProgram {
|
||||
|
@ -30,11 +31,6 @@ export class UnrecognizedProgram implements MultisigInstruction {
|
|||
return new UnrecognizedProgram(instruction);
|
||||
}
|
||||
}
|
||||
|
||||
export class PythMultisigInstruction implements MultisigInstruction {
|
||||
readonly program = MultisigInstructionProgram.PythOracle;
|
||||
}
|
||||
|
||||
export class MultisigParser {
|
||||
readonly pythOracleAddress: PublicKey;
|
||||
readonly wormholeBridgeAddress: PublicKey | undefined;
|
||||
|
@ -61,6 +57,8 @@ export class MultisigParser {
|
|||
return WormholeMultisigInstruction.fromTransactionInstruction(
|
||||
instruction
|
||||
);
|
||||
} else if (instruction.programId.equals(this.pythOracleAddress)) {
|
||||
return PythMultisigInstruction.fromTransactionInstruction(instruction);
|
||||
} else {
|
||||
return UnrecognizedProgram.fromTransactionInstruction(instruction);
|
||||
}
|
||||
|
|
|
@ -6,5 +6,6 @@ export const WORMHOLE_ADDRESS: Record<PythCluster, PublicKey | undefined> = {
|
|||
pythtest: new PublicKey("EUrRARh92Cdc54xrDn6qzaqjA77NRrCcfbr8kPwoTL4z"),
|
||||
devnet: new PublicKey("3u8hJUVTA4jH1wYAyUur7FFZVQ8H635K3tSHHF4ssjQ5"),
|
||||
pythnet: new PublicKey("H3fxXJ86ADW2PNuDDmZJg6mzTtPxkYCpNuQUTgmJ7AjU"),
|
||||
localnet: new PublicKey("gMYYig2utAxVoXnM9UhtTWrt8e7x2SVBZqsWZJeT5Gw"),
|
||||
testnet: undefined,
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue