Skip to content

Commit fdb2c5e

Browse files
authored
[Xc admin] centralize some things (#527)
* Checkpoint * Checkpoint * Prettify * Fix typo * Move bpf upgradable loader * Add file
1 parent f9e0145 commit fdb2c5e

File tree

8 files changed

+118
-40
lines changed

8 files changed

+118
-40
lines changed

governance/xc-admin/packages/xc-admin-cli/src/index.ts

Lines changed: 54 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,22 +4,26 @@ import {
44
TransactionInstruction,
55
SYSVAR_RENT_PUBKEY,
66
SYSVAR_CLOCK_PUBKEY,
7+
AccountMeta,
78
} from "@solana/web3.js";
89
import { program } from "commander";
910
import { PythCluster } from "@pythnetwork/client/lib/cluster";
1011
import { getPythClusterApiUrl } from "@pythnetwork/client/lib/cluster";
11-
import { AnchorError, AnchorProvider, Program } from "@coral-xyz/anchor";
12+
import { AnchorProvider, Program } from "@coral-xyz/anchor";
1213
import fs from "fs";
1314
import SquadsMesh from "@sqds/mesh";
1415
import NodeWallet from "@coral-xyz/anchor/dist/cjs/nodewallet";
15-
import { proposeInstructions } from "xc-admin-common";
16-
17-
const PROGRAM_AUTHORITY_ESCROW = new PublicKey(
18-
"escMHe7kSqPcDHx4HU44rAHhgdTLBZkUrU39aN8kMcL"
19-
);
20-
const BPF_UPGRADABLE_LOADER = new PublicKey(
21-
"BPFLoaderUpgradeab1e11111111111111111111111"
22-
);
16+
import {
17+
BPF_UPGRADABLE_LOADER,
18+
getMultisigCluster,
19+
getProposalInstructions,
20+
isRemoteCluster,
21+
mapKey,
22+
MultisigParser,
23+
PROGRAM_AUTHORITY_ESCROW,
24+
proposeInstructions,
25+
WORMHOLE_ADDRESS,
26+
} from "xc-admin-common";
2327

2428
const mutlisigCommand = (name: string, description: string) =>
2529
program
@@ -58,7 +62,11 @@ mutlisigCommand(
5862
const current: PublicKey = new PublicKey(options.current);
5963
const vault: PublicKey = new PublicKey(options.vault);
6064

61-
const squad = SquadsMesh.endpoint(getPythClusterApiUrl(cluster), wallet);
65+
const isRemote = isRemoteCluster(cluster);
66+
const squad = SquadsMesh.endpoint(
67+
getPythClusterApiUrl(getMultisigCluster(cluster)),
68+
wallet
69+
);
6270
const msAccount = await squad.getMultisig(vault);
6371
const vaultAuthority = squad.getAuthorityPDA(
6472
msAccount.publicKey,
@@ -73,6 +81,7 @@ mutlisigCommand(
7381
AnchorProvider.defaultOptions()
7482
)
7583
);
84+
7685
const programAuthorityEscrow = new Program(
7786
programAuthorityEscrowIdl!,
7887
PROGRAM_AUTHORITY_ESCROW,
@@ -91,14 +100,20 @@ mutlisigCommand(
91100
.accept()
92101
.accounts({
93102
currentAuthority: current,
94-
newAuthority: vaultAuthority,
103+
newAuthority: mapKey(vaultAuthority),
95104
programAccount: programId,
96105
programDataAccount,
97106
bpfUpgradableLoader: BPF_UPGRADABLE_LOADER,
98107
})
99108
.instruction();
100109

101-
await proposeInstructions(squad, vault, [proposalInstruction], false);
110+
await proposeInstructions(
111+
squad,
112+
vault,
113+
[proposalInstruction],
114+
isRemote,
115+
WORMHOLE_ADDRESS[getMultisigCluster(cluster)]
116+
);
102117
});
103118

104119
mutlisigCommand("upgrade-program", "Upgrade a program from a buffer")
@@ -150,4 +165,31 @@ mutlisigCommand("upgrade-program", "Upgrade a program from a buffer")
150165
await proposeInstructions(squad, vault, [proposalInstruction], false);
151166
});
152167

168+
program
169+
.command("parse-transaction")
170+
.description("Parse a transaction sitting in the multisig")
171+
.requiredOption("-c, --cluster <network>", "solana cluster to use")
172+
.requiredOption("-t, --transaction <pubkey>", "path to the operations key")
173+
.action(async (options: any) => {
174+
const cluster = options.cluster;
175+
const transaction: PublicKey = new PublicKey(options.transaction);
176+
const squad = SquadsMesh.endpoint(
177+
getPythClusterApiUrl(cluster),
178+
new NodeWallet(new Keypair())
179+
);
180+
const onChainInstructions = await getProposalInstructions(
181+
squad,
182+
await squad.getTransaction(new PublicKey(transaction))
183+
);
184+
const parser = MultisigParser.fromCluster(cluster);
185+
const parsed = onChainInstructions.map((ix) =>
186+
parser.parseInstruction({
187+
programId: ix.programId,
188+
data: ix.data as Buffer,
189+
keys: ix.keys as AccountMeta[],
190+
})
191+
);
192+
console.log(JSON.stringify(parsed, null, 2));
193+
});
194+
153195
program.parse();
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import { PublicKey } from "@solana/web3.js";
2+
3+
export const PROGRAM_AUTHORITY_ESCROW = new PublicKey(
4+
"escMHe7kSqPcDHx4HU44rAHhgdTLBZkUrU39aN8kMcL"
5+
);
6+
7+
export const BPF_UPGRADABLE_LOADER = new PublicKey(
8+
"BPFLoaderUpgradeab1e11111111111111111111111"
9+
);
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import { PythCluster } from "@pythnetwork/client/lib/cluster";
2+
import { Cluster } from "@solana/web3.js";
3+
4+
/**
5+
* Return whether the cluster is governed remotely or not. For example Pythnet is governed remotely by a mainnet multisig.
6+
*/
7+
export function isRemoteCluster(cluster: PythCluster) {
8+
return cluster == "pythnet" || cluster == "pythtest";
9+
}
10+
11+
/**
12+
* For cluster that are governed remotely (ex : Pythnet from Mainnet) return the network where the multisig lives
13+
*/
14+
export function getMultisigCluster(cluster: PythCluster): Cluster | "localnet" {
15+
switch (cluster) {
16+
case "pythnet":
17+
return "mainnet-beta";
18+
case "pythtest":
19+
return "devnet";
20+
default:
21+
return cluster;
22+
}
23+
}

governance/xc-admin/packages/xc-admin-common/src/index.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,6 @@ export * from "./propose";
33
export * from "./governance_payload";
44
export * from "./wormhole";
55
export * from "./multisig_transaction";
6+
export * from "./cluster";
7+
export * from "./remote_executor";
8+
export * from "./bpf_upgradable_loader";
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import { PublicKey } from "@solana/web3.js";
2+
3+
/**
4+
* Address of the remote executor (same on all networks)
5+
*/
6+
export const REMOTE_EXECUTOR_ADDRESS = new PublicKey(
7+
"exe6S3AxPVNmy46L4Nj6HrnnAVQUhwyYzMSNcnRn3qq"
8+
);
9+
10+
/**
11+
* Map key to the key that a remote executor will use when it receives a message from `key`
12+
* @param key the key to map
13+
* @returns the key that the remote executor will use
14+
*/
15+
export function mapKey(key: PublicKey): PublicKey {
16+
return PublicKey.findProgramAddressSync(
17+
[Buffer.from("EXECUTOR_KEY"), key.toBytes()],
18+
REMOTE_EXECUTOR_ADDRESS
19+
)[0];
20+
}

governance/xc-admin/packages/xc-admin-frontend/components/tabs/AddRemovePublishers.tsx

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,10 @@ import { WalletModalButton } from '@solana/wallet-adapter-react-ui'
99
import { PublicKey, TransactionInstruction } from '@solana/web3.js'
1010
import { Fragment, useContext, useEffect, useState } from 'react'
1111
import toast from 'react-hot-toast'
12-
import { proposeInstructions } from 'xc-admin-common'
12+
import { proposeInstructions, getMultisigCluster } from 'xc-admin-common'
1313
import { ClusterContext } from '../../contexts/ClusterContext'
1414
import { usePythContext } from '../../contexts/PythContext'
15-
import {
16-
getMultisigCluster,
17-
SECURITY_MULTISIG,
18-
useMultisig,
19-
} from '../../hooks/useMultisig'
15+
import { SECURITY_MULTISIG, useMultisig } from '../../hooks/useMultisig'
2016
import { capitalizeFirstLetter } from '../../utils/capitalizeFirstLetter'
2117
import ClusterSwitch from '../ClusterSwitch'
2218
import Modal from '../common/Modal'

governance/xc-admin/packages/xc-admin-frontend/components/tabs/UpdatePermissions.tsx

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,14 @@ import {
1616
import copy from 'copy-to-clipboard'
1717
import { useContext, useEffect, useState } from 'react'
1818
import toast from 'react-hot-toast'
19-
import { proposeInstructions } from 'xc-admin-common'
20-
import { ClusterContext } from '../../contexts/ClusterContext'
21-
import { usePythContext } from '../../contexts/PythContext'
2219
import {
20+
proposeInstructions,
2321
getMultisigCluster,
24-
UPGRADE_MULTISIG,
25-
useMultisig,
26-
} from '../../hooks/useMultisig'
22+
BPF_UPGRADABLE_LOADER,
23+
} from 'xc-admin-common'
24+
import { ClusterContext } from '../../contexts/ClusterContext'
25+
import { usePythContext } from '../../contexts/PythContext'
26+
import { UPGRADE_MULTISIG, useMultisig } from '../../hooks/useMultisig'
2727
import CopyIcon from '../../images/icons/copy.inline.svg'
2828
import { capitalizeFirstLetter } from '../../utils/capitalizeFirstLetter'
2929
import ClusterSwitch from '../ClusterSwitch'
@@ -53,10 +53,6 @@ const DEFAULT_DATA: UpdatePermissionsProps[] = [
5353
},
5454
]
5555

56-
const BPF_UPGRADABLE_LOADER = new PublicKey(
57-
'BPFLoaderUpgradeab1e11111111111111111111111'
58-
)
59-
6056
const columnHelper = createColumnHelper<UpdatePermissionsProps>()
6157

6258
const defaultColumns = [

governance/xc-admin/packages/xc-admin-frontend/hooks/useMultisig.ts

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,21 +4,10 @@ import { Cluster, Connection, PublicKey } from '@solana/web3.js'
44
import SquadsMesh from '@sqds/mesh'
55
import { TransactionAccount } from '@sqds/mesh/lib/types'
66
import { useContext, useEffect, useRef, useState } from 'react'
7-
import { getProposals } from 'xc-admin-common'
7+
import { getMultisigCluster, getProposals } from 'xc-admin-common'
88
import { ClusterContext } from '../contexts/ClusterContext'
99
import { pythClusterApiUrls } from '../utils/pythClusterApiUrl'
1010

11-
export function getMultisigCluster(cluster: PythCluster): Cluster | 'localnet' {
12-
switch (cluster) {
13-
case 'pythnet':
14-
return 'mainnet-beta'
15-
case 'pythtest':
16-
return 'devnet'
17-
default:
18-
return cluster
19-
}
20-
}
21-
2211
export const UPGRADE_MULTISIG: Record<Cluster | 'localnet', PublicKey> = {
2312
'mainnet-beta': new PublicKey('FVQyHcooAtThJ83XFrNnv74BcinbRH3bRmfFamAHBfuj'),
2413
testnet: new PublicKey('FVQyHcooAtThJ83XFrNnv74BcinbRH3bRmfFamAHBfuj'),

0 commit comments

Comments
 (0)