Skip to content

Commit a25afb5

Browse files
committed
cli: check mint authority before deployment (solana)
1 parent 8ca2c33 commit a25afb5

File tree

1 file changed

+48
-15
lines changed

1 file changed

+48
-15
lines changed

cli/src/index.ts

+48-15
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@ import chalk from "chalk";
1212
import yargs from "yargs";
1313
import { $ } from "bun";
1414
import { hideBin } from "yargs/helpers";
15-
import { Keypair, PublicKey } from "@solana/web3.js";
15+
import { Connection, Keypair, PublicKey } from "@solana/web3.js";
16+
import * as spl from "@solana/spl-token";
1617
import fs from "fs";
1718
import readline from "readline";
1819
import { ChainContext, UniversalAddress, Wormhole, assertChain, canonicalAddress, chainToPlatform, chains, isNetwork, networks, platforms, signSendWait, toUniversal, type AccountAddress, type Chain, type ChainAddress, type ConfigOverrides, type Network, type Platform } from "@wormhole-foundation/sdk";
@@ -966,6 +967,9 @@ async function deploySolana<N extends Network, C extends SolanaChains>(
966967
): Promise<ChainAddress<C>> {
967968
ensureNttRoot(pwd);
968969

970+
// TODO: if the binary is provided, we should not check addresses in the source tree. (so we should move around the control flow a bit)
971+
// TODO: factor out some of this into separate functions to help readability of this function (maybe even move to a different file)
972+
969973
const wormhole = ch.config.contracts.coreBridge;
970974
if (!wormhole) {
971975
console.error("Core bridge not found");
@@ -1030,6 +1034,49 @@ async function deploySolana<N extends Network, C extends SolanaChains>(
10301034
fs.writeFileSync(libRsPath, newLibRs);
10311035
}
10321036

1037+
1038+
// First we check that the provided mint's mint authority is the program's token authority PDA when in burning mode.
1039+
// This is checked in the program initialiser anyway, but we can save some
1040+
// time by checking it here and failing early (not to mention better
1041+
// diagnostics).
1042+
1043+
const emitter = NTT.pdas(providedProgramId).emitterAccount().toBase58();
1044+
const payerKeypair = Keypair.fromSecretKey(new Uint8Array(JSON.parse(fs.readFileSync(payer).toString())));
1045+
1046+
// can't do this yet.. need to init first.
1047+
// const {ntt, addresses} = await nttFromManager(ch, providedProgramId);
1048+
const ntt: SolanaNtt<N, C> = await ch.getProtocol("Ntt", {
1049+
ntt: {
1050+
manager: providedProgramId,
1051+
token: token,
1052+
transceiver: { wormhole: emitter },
1053+
}
1054+
}) as SolanaNtt<N, C>;
1055+
1056+
// get the mint authority of 'token'
1057+
const tokenMint = new PublicKey(token);
1058+
// const tokenInfo = await ch.connection.getTokenInfo(tokenMint);
1059+
const connection: Connection = await ch.getRpc();
1060+
const mintInfo = await connection.getAccountInfo(tokenMint)
1061+
if (!mintInfo) {
1062+
console.error(`Mint ${token} not found on ${ch.chain} ${ch.network}`);
1063+
process.exit(1);
1064+
}
1065+
const mint = spl.unpackMint(tokenMint, mintInfo, mintInfo.owner);
1066+
1067+
if (mode === "burning") {
1068+
const expectedMintAuthority = ntt.pdas.tokenAuthority().toBase58();
1069+
const actualMintAuthority: string | null = mint.mintAuthority?.toBase58() ?? null;
1070+
if (actualMintAuthority !== expectedMintAuthority) {
1071+
console.error(`Mint authority mismatch for ${token}`);
1072+
console.error(`Expected: ${expectedMintAuthority}`);
1073+
console.error(`Actual: ${actualMintAuthority}`);
1074+
console.error(`Set the mint authority to the program's token authority PDA with e.g.:`);
1075+
console.error(`spl-token authorize ${token} mint ${expectedMintAuthority}`);
1076+
process.exit(1);
1077+
}
1078+
}
1079+
10331080
let binary: string;
10341081

10351082
const skipDeploy = false;
@@ -1086,20 +1133,6 @@ async function deploySolana<N extends Network, C extends SolanaChains>(
10861133
// wait 3 seconds
10871134
await new Promise((resolve) => setTimeout(resolve, 3000));
10881135

1089-
const emitter = NTT.pdas(providedProgramId).emitterAccount().toBase58();
1090-
1091-
const payerKeypair = Keypair.fromSecretKey(new Uint8Array(JSON.parse(fs.readFileSync(payer).toString())));
1092-
1093-
// can't do this yet.. need to init first.
1094-
// const {ntt, addresses} = await nttFromManager(ch, providedProgramId);
1095-
const ntt: SolanaNtt<N, C> = await ch.getProtocol("Ntt", {
1096-
ntt: {
1097-
manager: providedProgramId,
1098-
token: token,
1099-
transceiver: { wormhole: emitter },
1100-
}
1101-
}) as SolanaNtt<N, C>;
1102-
11031136
const tx = ntt.initialize(
11041137
toUniversal(ch.chain, payerKeypair.publicKey.toBase58()),
11051138
{

0 commit comments

Comments
 (0)