Skip to content

Commit 863a983

Browse files
jayantkJayant Krishnamurthy
andauthored
Add set-is-active instruction and some minor tweaks (#317)
* add set-is-active instruction and some minor tweaks * stuff * whoops Co-authored-by: Jayant Krishnamurthy <jkrishnamurthy@jumptrading.com>
1 parent 57bdb09 commit 863a983

File tree

1 file changed

+162
-58
lines changed
  • third_party/pyth/multisig-wh-message-builder/src

1 file changed

+162
-58
lines changed

third_party/pyth/multisig-wh-message-builder/src/index.ts

Lines changed: 162 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,11 @@ import {
77
import * as anchor from "@project-serum/anchor";
88
import NodeWallet from "@project-serum/anchor/dist/cjs/nodewallet";
99
import {
10+
AccountMeta,
1011
Keypair,
1112
LAMPORTS_PER_SOL,
1213
PublicKey,
13-
SystemProgram,
14+
SystemProgram, TransactionInstruction,
1415
} from "@solana/web3.js";
1516
import Squads from "@sqds/mesh";
1617
import bs58 from "bs58";
@@ -45,18 +46,51 @@ program
4546
"keys/key.json"
4647
)
4748
.option("-p, --payload <hex-string>", "payload to sign", "0xdeadbeef")
48-
.action((options) => {
49-
createMultisigTx(
49+
.action(async (options) => {
50+
const squad = await getSquadsClient(options.cluster, options.ledger, options.ledgerDerivationAccount, options.ledgerDerivationChange, options.wallet);
51+
await createWormholeMsgMultisigTx(
5052
options.cluster,
51-
new PublicKey(options.vaultAddress),
53+
squad,
5254
options.ledger,
53-
options.ledgerDerivationAccount,
54-
options.ledgerDerivationChange,
55-
options.wallet,
55+
new PublicKey(options.vaultAddress),
5656
options.payload
5757
);
5858
});
5959

60+
program
61+
.command("set-is-active")
62+
.description("Create a new multisig transaction to set the attester is-active flag")
63+
.option("-c, --cluster <network>", "solana cluster to use", "devnet")
64+
.requiredOption("-v, --vault-address <address>", "multisig vault address")
65+
.option("-l, --ledger", "use ledger")
66+
.option(
67+
"-lda, --ledger-derivation-account <number>",
68+
"ledger derivation account to use"
69+
)
70+
.option(
71+
"-ldc, --ledger-derivation-change <number>",
72+
"ledger derivation change to use"
73+
)
74+
.option(
75+
"-w, --wallet <filepath>",
76+
"multisig wallet secret key filepath",
77+
"keys/key.json"
78+
)
79+
.option("-a, --attester <program id>")
80+
.option("-i, --is-active <true/false>", "set the isActive field to this value", true)
81+
.action(async (options) => {
82+
const squad = await getSquadsClient(options.cluster, options.ledger, options.ledgerDerivationAccount, options.ledgerDerivationChange, options.wallet);
83+
const msAccount = await squad.getMultisig(options.vaultAddress);
84+
const vaultAuthority = squad.getAuthorityPDA(
85+
msAccount.publicKey,
86+
msAccount.authorityIndex
87+
);
88+
const attesterProgramId = new PublicKey(options.attester);
89+
const txKey = await createTx(squad, options.ledger, new PublicKey(options.vaultAddress));
90+
const instructions = [await setIsActiveIx(vaultAuthority, vaultAuthority, attesterProgramId, options.active)];
91+
await addInstructionsToTx(squad, options.ledger, txKey, instructions);
92+
});
93+
6094
program
6195
.command("execute")
6296
.description("Execute a multisig transaction that is ready")
@@ -112,6 +146,110 @@ const solanaClusterMappingToWormholeNetwork: Record<Cluster, WormholeNetwork> =
112146
"mainnet-beta": "MAINNET",
113147
};
114148

149+
async function getSquadsClient(cluster: Cluster,
150+
ledger: boolean,
151+
ledgerDerivationAccount: number | undefined,
152+
ledgerDerivationChange: number | undefined,
153+
walletPath: string,
154+
) {
155+
let wallet: LedgerNodeWallet | NodeWallet;
156+
if (ledger) {
157+
console.log("Please connect to ledger...");
158+
wallet = await LedgerNodeWallet.createWallet(
159+
ledgerDerivationAccount,
160+
ledgerDerivationChange
161+
);
162+
console.log(`Ledger connected! ${wallet.publicKey.toBase58()}`);
163+
} else {
164+
wallet = new NodeWallet(
165+
Keypair.fromSecretKey(
166+
Uint8Array.from(JSON.parse(fs.readFileSync(walletPath, "ascii")))
167+
)
168+
);
169+
console.log(`Loaded wallet with address: ${wallet.publicKey.toBase58()}`);
170+
}
171+
const squad =
172+
cluster === "devnet" ? Squads.devnet(wallet) : Squads.mainnet(wallet);
173+
return squad;
174+
}
175+
176+
async function createTx(
177+
squad: Squads,
178+
ledger: boolean,
179+
vault: PublicKey,
180+
): Promise<PublicKey> {
181+
const msAccount = await squad.getMultisig(vault);
182+
183+
console.log("Creating new transaction...");
184+
if (ledger) {
185+
console.log("Please approve the transaction on your ledger device...");
186+
}
187+
const newTx = await squad.createTransaction(
188+
msAccount.publicKey,
189+
msAccount.authorityIndex
190+
);
191+
console.log(`Tx Address: ${newTx.publicKey.toBase58()}`);
192+
193+
return newTx.publicKey;
194+
}
195+
196+
/** Adds the given instructions to the squads transaction at `txKey` and activates the transaction (makes it ready for signing). */
197+
async function addInstructionsToTx(
198+
squad: Squads,
199+
ledger: boolean,
200+
txKey: PublicKey,
201+
instructions: TransactionInstruction[]
202+
) {
203+
for (let i = 0; i < instructions.length; i++) {
204+
console.log(`Adding instruction ${i}/${instructions.length} to transaction...`);
205+
if (ledger) {
206+
console.log("Please approve the transaction on your ledger device...");
207+
}
208+
await squad.addInstruction(txKey, instructions[i]);
209+
}
210+
211+
console.log("Activating transaction...");
212+
if (ledger)
213+
console.log("Please approve the transaction on your ledger device...");
214+
await squad.activateTransaction(txKey);
215+
console.log("Transaction created.");
216+
}
217+
218+
async function setIsActiveIx(
219+
payerKey: PublicKey,
220+
opsOwnerKey: PublicKey,
221+
attesterProgramId: PublicKey,
222+
isActive: boolean
223+
): Promise<TransactionInstruction> {
224+
const configKey = PublicKey.createProgramAddressSync([Buffer.from("pyth2wormhole-config-v3")], attesterProgramId)
225+
const config: AccountMeta = {
226+
pubkey: configKey,
227+
isSigner: false,
228+
isWritable: true,
229+
}
230+
231+
const opsOwner: AccountMeta = {
232+
pubkey: opsOwnerKey,
233+
isSigner: true,
234+
isWritable: true,
235+
}
236+
const payer: AccountMeta = {
237+
pubkey: payerKey,
238+
isSigner: true,
239+
isWritable: true,
240+
}
241+
242+
const isActiveInt = (isActive === true) ? 1 : 0;
243+
// first byte is the isActive instruction, second byte is true/false
244+
const data = new Buffer([4, isActiveInt])
245+
246+
return {
247+
keys: [config, opsOwner, payer],
248+
programId: attesterProgramId,
249+
data: data,
250+
}
251+
}
252+
115253
async function getWormholeMessageIx(
116254
cluster: Cluster,
117255
payer: PublicKey,
@@ -155,33 +293,13 @@ async function getWormholeMessageIx(
155293
];
156294
}
157295

158-
async function createMultisigTx(
296+
async function createWormholeMsgMultisigTx(
159297
cluster: Cluster,
160-
vault: PublicKey,
298+
squad: Squads,
161299
ledger: boolean,
162-
ledgerDerivationAccount: number | undefined,
163-
ledgerDerivationChange: number | undefined,
164-
walletPath: string,
300+
vault: PublicKey,
165301
payload: string
166302
) {
167-
let wallet: LedgerNodeWallet | NodeWallet;
168-
if (ledger) {
169-
console.log("Please connect to ledger...");
170-
wallet = await LedgerNodeWallet.createWallet(
171-
ledgerDerivationAccount,
172-
ledgerDerivationChange
173-
);
174-
console.log(`Ledger connected! ${wallet.publicKey.toBase58()}`);
175-
} else {
176-
wallet = new NodeWallet(
177-
Keypair.fromSecretKey(
178-
Uint8Array.from(JSON.parse(fs.readFileSync(walletPath, "ascii")))
179-
)
180-
);
181-
console.log(`Loaded wallet with address: ${wallet.publicKey.toBase58()}`);
182-
}
183-
const squad =
184-
cluster === "devnet" ? Squads.devnet(wallet) : Squads.mainnet(wallet);
185303
const msAccount = await squad.getMultisig(vault);
186304

187305
const emitter = squad.getAuthorityPDA(
@@ -190,18 +308,13 @@ async function createMultisigTx(
190308
);
191309
console.log(`Emitter Address: ${emitter.toBase58()}`);
192310

193-
console.log("Creating new transaction...");
194-
if (ledger)
195-
console.log("Please approve the transaction on your ledger device...");
196-
const newTx = await squad.createTransaction(
197-
msAccount.publicKey,
198-
msAccount.authorityIndex
199-
);
200-
console.log(`Tx Address: ${newTx.publicKey.toBase58()}`);
311+
const txKey = await createTx(squad, ledger, vault);
201312

202313
const message = Keypair.generate();
314+
315+
fs.mkdirSync('keys', {recursive: true});
203316
// save message to Uint8 array keypair file called mesage.json
204-
fs.writeFileSync(`keys/message.json`, `[${message.secretKey.toString()}]`);
317+
fs.writeFileSync(`keys/message-${txKey.toBase58()}.json`, `[${message.secretKey.toString()}]`);
205318
console.log(`Message Address: ${message.publicKey.toBase58()}`);
206319

207320
console.log("Creating wormhole instructions...");
@@ -215,22 +328,7 @@ async function createMultisigTx(
215328
);
216329
console.log("Wormhole instructions created.");
217330

218-
console.log("Adding instruction 1/2 to transaction...");
219-
if (ledger)
220-
console.log("Please approve the transaction on your ledger device...");
221-
// transfer sol to the message account
222-
await squad.addInstruction(newTx.publicKey, wormholeIxs[0]);
223-
console.log("Adding instruction 2/2 to transaction...");
224-
if (ledger)
225-
console.log("Please approve the transaction on your ledger device...");
226-
// wormhole post message ix
227-
await squad.addInstruction(newTx.publicKey, wormholeIxs[1]);
228-
229-
console.log("Activating transaction...");
230-
if (ledger)
231-
console.log("Please approve the transaction on your ledger device...");
232-
await squad.activateTransaction(newTx.publicKey);
233-
console.log("Transaction created.");
331+
await addInstructionsToTx(squad, ledger, txKey, wormholeIxs);
234332
}
235333

236334
async function executeMultisigTx(
@@ -328,6 +426,12 @@ async function executeMultisigTx(
328426
}`
329427
);
330428

429+
console.log(
430+
"Sleeping for 10 seconds to allow guardians enough time to get the sequence number..."
431+
);
432+
await new Promise((resolve) => setTimeout(resolve, 10000));
433+
434+
331435
const txDetails = await squad.connection.getParsedTransaction(
332436
signature,
333437
"confirmed"
@@ -341,11 +445,10 @@ async function executeMultisigTx(
341445
);
342446
console.log(`Sequence number: ${sequenceNumber}`);
343447

344-
// sleep for 5 seconds
345448
console.log(
346-
"Sleeping for 5 seconds to allow guardians enough time to create VAA..."
449+
"Sleeping for 10 seconds to allow guardians enough time to create VAA..."
347450
);
348-
await new Promise((resolve) => setTimeout(resolve, 5000));
451+
await new Promise((resolve) => setTimeout(resolve, 10000));
349452

350453
// fetch VAA
351454
console.log("Fetching VAA...");
@@ -357,6 +460,7 @@ async function executeMultisigTx(
357460
const { vaaBytes } = await response.json();
358461
console.log(`VAA (Base64): ${vaaBytes}`);
359462
const parsedVaa = await parse(vaaBytes);
463+
console.log(`VAA (Hex): ${Buffer.from(vaaBytes).toString('hex')}`)
360464
console.log(`Emitter chain: ${parsedVaa.emitter_chain}`);
361465
console.log(`Nonce: ${parsedVaa.nonce}`);
362466
console.log(`Payload: ${Buffer.from(parsedVaa.payload).toString('hex')}`);

0 commit comments

Comments
 (0)