Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Deployment scripts for Solana #688

Merged
merged 19 commits into from
Aug 21, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions cross-chain/solana/.env.template
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export AUTHORITY=<path_to_keypair_deployer>
export THRESHOLD_COUNCIL_MULTISIG=<multisig_address>
export NETWORK=<solana-devnet, mainnet>
export CLUSTER=<devnet, mainnet>
export ANCHOR_PROVIDER_URL=<http://localhost:8899, https://api.devnet.solana.com, https://api.mainnet-beta.solana.com>
export ANCHOR_WALLET=<path_to_keypair_deployer>
7 changes: 5 additions & 2 deletions cross-chain/solana/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,12 @@
.anchor
.prettierrc.json
.DS_Store
target
/target/*
**/*.rs.bk
node_modules
test-ledger
artifacts-mainnet
artifacts-testnet
artifacts-testnet
.env
!/target/idl/
!/target/idl/*
3 changes: 3 additions & 0 deletions cross-chain/solana/.prettierrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module.exports = {
...require("@thesis-co/prettier-config"),
}
8 changes: 7 additions & 1 deletion cross-chain/solana/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,10 @@ lint:
cargo fmt --check
cargo check --features "mainnet" --no-default-features
cargo check --features "solana-devnet" --no-default-features
cargo clippy --no-deps --all-targets -- -D warnings
cargo clippy --no-deps --all-targets -- -D warnings

init_programs:
ts-node --files ./deploy/init.ts

transfer_authority:
ts-node --files ./deploy/transfer_authority.ts
46 changes: 46 additions & 0 deletions cross-chain/solana/deploy/helpers/consts.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { WRAPPED_TBTC_MINT } from "./../../tests/helpers/consts"
export const WH_ARBITRUM_CHAIN_ID = 23

export const WH_OPTIMISM_CHAIN_ID = 24

export const WH_POLYGON_CHAIN_ID = 5

export const WH_BASE_CHAIN_ID = 30

export const WH_SOLANA_CHAIN_ID = 1

// EVM addresses converted to 32 bytes. 0x is trimmed intentionally as the input
// param requires it without leading 0x.

export const ARBITRUM_GATEWAY_ADDRESS_TESTNET =
"00000000000000000000000031a15e213b59e230b45e8c5c99dafac3d1236ee2"

export const ARBITRUM_GATEWAY_ADDRESS_MAINNET =
"0000000000000000000000001293a54e160d1cd7075487898d65266081a15458"

export const OPTIMISM_GATEWAY_ADDRESS_TESTNET =
"0000000000000000000000006449F4381f3d63bDfb36B3bDc375724aD3cD4621"
export const OPTIMISM_GATEWAY_ADDRESS_MAINNET =
"0000000000000000000000001293a54e160D1cd7075487898d65266081A15458"

export const POLYGON_GATEWAY_ADDRESS_TESTNET =
"00000000000000000000000091Fe7128f74dBd4F031ea3D90FC5Ea4DCfD81818"
export const POLYGON_GATEWAY_ADDRESS_MAINNET =
"00000000000000000000000009959798B95d00a3183d20FaC298E4594E599eab"

export const BASE_GATEWAY_ADDRESS_TESTNET =
"000000000000000000000000e3e0511EEbD87F08FbaE4486419cb5dFB06e1343"
export const BASE_GATEWAY_ADDRESS_MAINNET =
"00000000000000000000000009959798B95d00a3183d20FaC298E4594E599eab"

export const SOLANA_GATEWAY_ADDRESS_TESTNET =
"87MEvHZCXE3ML5rrmh5uX1FbShHmRXXS32xJDGbQ7h5t"
export const SOLANA_GATEWAY_ADDRESS_MAINNET =
"87MEvHZCXE3ML5rrmh5uX1FbShHmRXXS32xJDGbQ7h5t"

// deriveWrappedMintKey("DZnkkTmCiFWfYTfT41X3Rd1kDgozqzxWaHqsw6W4x2oe", 2, "0x679874fbe6d4e7cc54a59e315ff1eb266686a937")
export const WRAPPED_TBTC_MINT_TESTNET =
"FMYvcyMJJ22whB9m3T5g1oPKwM6jpLnFBXnrY6eXmCrp"
// deriveWrappedMintKey("wormDTUJ6AWPNvk59vGQbDvGJmqbDTdgWgAqcLBCgUb", 2, "0x18084fbA666a33d37592fA2633fD49a74DD93a88")
export const WRAPPED_TBTC_MINT_MAINNET =
"25rXTx9zDZcHyTav5sRqM6YBvTGu9pPH9yv83uAEqbgG"
294 changes: 294 additions & 0 deletions cross-chain/solana/deploy/init.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,294 @@
import * as anchor from "@coral-xyz/anchor"
import fs from "fs"
import { PublicKey, Keypair } from "@solana/web3.js"
import dotenv from "dotenv"
import { Program } from "@coral-xyz/anchor"
import { Tbtc } from "../target/types/tbtc"
import { WormholeGateway } from "../target/types/wormhole_gateway"
import { PROGRAM_ID as METADATA_PROGRAM_ID } from "@metaplex-foundation/mpl-token-metadata"
import * as consts from "./helpers/consts"

async function run(): Promise<void> {
dotenv.config({ path: "../solana.env" })

anchor.setProvider(anchor.AnchorProvider.env())

const tbtcProgram = anchor.workspace.Tbtc as Program<Tbtc>
const wormholeGatewayProgram = anchor.workspace
.WormholeGateway as Program<WormholeGateway>

// This wallet deployed the program and is also an authority
const authority = loadKey(process.env.AUTHORITY).publicKey

const mint = PublicKey.findProgramAddressSync(
[Buffer.from("tbtc-mint")],
tbtcProgram.programId
)[0]

const config = PublicKey.findProgramAddressSync(
[Buffer.from("config")],
tbtcProgram.programId
)[0]

const guardians = PublicKey.findProgramAddressSync(
[Buffer.from("guardians")],
tbtcProgram.programId
)[0]

const minters = PublicKey.findProgramAddressSync(
[Buffer.from("minters")],
tbtcProgram.programId
)[0]

const tbtcMetadata = PublicKey.findProgramAddressSync(
[Buffer.from("metadata"), METADATA_PROGRAM_ID.toBuffer(), mint.toBuffer()],
METADATA_PROGRAM_ID
)[0]

const mplTokenMetadataProgram = METADATA_PROGRAM_ID

// Initalize tbtc program
await tbtcProgram.methods
.initialize()
.accounts({
mint,
config,
guardians,
minters,
authority,
tbtcMetadata,
mplTokenMetadataProgram,
})
.rpc()

const minter = PublicKey.findProgramAddressSync(
[Buffer.from("redeemer")],
wormholeGatewayProgram.programId
)[0]

const mintingLimit = "18446744073709551615" // Max u64
let WRAPPED_TBTC = consts.WRAPPED_TBTC_MINT_TESTNET
if (process.env.CLUSTER === "mainnet") {
WRAPPED_TBTC = consts.WRAPPED_TBTC_MINT_MAINNET
}
const WRAPPED_TBTC_MINT = new PublicKey(WRAPPED_TBTC)

const gatewayWrappedTbtcToken = PublicKey.findProgramAddressSync(
[Buffer.from("wrapped-token")],
wormholeGatewayProgram.programId
)[0]

const tokenBridgeSender = PublicKey.findProgramAddressSync(
[Buffer.from("sender")],
wormholeGatewayProgram.programId
)[0]

// NOTE: It might happen on mainnet that tbtc won't be initialized if running this
// script in one shot.
// The simplest solution is just to wait a bit and then proceed with wormhole_gateway
// initializtion.

// Initialize wormhole gateway
await wormholeGatewayProgram.methods
.initialize(new anchor.BN(mintingLimit))
.accounts({
authority,
custodian: minter,
tbtcMint: mint,
wrappedTbtcMint: WRAPPED_TBTC_MINT,
wrappedTbtcToken: gatewayWrappedTbtcToken,
tokenBridgeSender,
})
.rpc()

console.log("Initialized wormhole gateway program..")

const minterInfo = PublicKey.findProgramAddressSync(
[Buffer.from("minter-info"), minter.toBuffer()],
tbtcProgram.programId
)[0]

// Adding a minter (wormholeGateway)
await tbtcProgram.methods
.addMinter()
.accounts({
config,
authority,
minters,
minterInfo,
minter,
})
.rpc()

console.log("Added a minter..")

// Point to devnet addresses by default
let ARBITRUM_GATEWAY = consts.ARBITRUM_GATEWAY_ADDRESS_TESTNET
let OPTIMISM_GATEWAY = consts.OPTIMISM_GATEWAY_ADDRESS_TESTNET
let POLYGON_GATEWAY = consts.POLYGON_GATEWAY_ADDRESS_TESTNET
let BASE_GATEWAY = consts.BASE_GATEWAY_ADDRESS_TESTNET
let SOLANA_GATEWAY = consts.SOLANA_GATEWAY_ADDRESS_TESTNET
if (process.env.CLUSTER === "mainnet") {
ARBITRUM_GATEWAY = consts.ARBITRUM_GATEWAY_ADDRESS_MAINNET
OPTIMISM_GATEWAY = consts.OPTIMISM_GATEWAY_ADDRESS_MAINNET
POLYGON_GATEWAY = consts.POLYGON_GATEWAY_ADDRESS_MAINNET
BASE_GATEWAY = consts.BASE_GATEWAY_ADDRESS_MAINNET
SOLANA_GATEWAY = consts.SOLANA_GATEWAY_ADDRESS_MAINNET
}

// Updating with Arbitrum
const arbiArgs = {
chain: consts.WH_ARBITRUM_CHAIN_ID,
address: Array.from(Buffer.alloc(32, ARBITRUM_GATEWAY, "hex")),
}

const encodedArbiChain = Buffer.alloc(2)
encodedArbiChain.writeUInt16LE(consts.WH_ARBITRUM_CHAIN_ID)
const gatewayArbiInfo = PublicKey.findProgramAddressSync(
[Buffer.from("gateway-info"), encodedArbiChain],
wormholeGatewayProgram.programId
)[0]

await wormholeGatewayProgram.methods
.updateGatewayAddress(arbiArgs)
.accounts({
custodian: minter,
gatewayInfo: gatewayArbiInfo,
authority,
})
.rpc()

console.log(
"Updated Solana gateway with Arbitrum..",
Array.from(new PublicKey(ARBITRUM_GATEWAY).toBuffer())
)

// Updating with Optimism
const optiArgs = {
chain: consts.WH_OPTIMISM_CHAIN_ID,
address: Array.from(Buffer.alloc(32, OPTIMISM_GATEWAY, "hex")),
}

const encodedOptiChain = Buffer.alloc(2)
encodedOptiChain.writeUInt16LE(consts.WH_OPTIMISM_CHAIN_ID)
const gatewayOptiInfo = PublicKey.findProgramAddressSync(
[Buffer.from("gateway-info"), encodedOptiChain],
wormholeGatewayProgram.programId
)[0]

await wormholeGatewayProgram.methods
.updateGatewayAddress(optiArgs)
.accounts({
custodian: minter,
gatewayInfo: gatewayOptiInfo,
authority,
})
.rpc()

console.log(
"Updated Solana gateway with Optimism..",
Array.from(new PublicKey(OPTIMISM_GATEWAY).toBuffer())
)

// Updating with Polygon
const polyArgs = {
chain: consts.WH_POLYGON_CHAIN_ID,
address: Array.from(Buffer.alloc(32, POLYGON_GATEWAY, "hex")),
}

const encodedPolyChain = Buffer.alloc(2)
encodedPolyChain.writeUInt16LE(consts.WH_POLYGON_CHAIN_ID)
const gatewayPolyInfo = PublicKey.findProgramAddressSync(
[Buffer.from("gateway-info"), encodedPolyChain],
wormholeGatewayProgram.programId
)[0]

await wormholeGatewayProgram.methods
.updateGatewayAddress(polyArgs)
.accounts({
custodian: minter,
gatewayInfo: gatewayPolyInfo,
authority,
})
.rpc()

console.log(
"Updated Solana gateway with Polygon..",
Array.from(new PublicKey(POLYGON_GATEWAY).toBuffer())
)

// Updating with BASE
const baseArgs = {
chain: consts.WH_BASE_CHAIN_ID,
address: Array.from(Buffer.alloc(32, BASE_GATEWAY, "hex")),
}

const encodedBaseChain = Buffer.alloc(2)
encodedBaseChain.writeUInt16LE(consts.WH_BASE_CHAIN_ID)
const gatewayBaseInfo = PublicKey.findProgramAddressSync(
[Buffer.from("gateway-info"), encodedBaseChain],
wormholeGatewayProgram.programId
)[0]

await wormholeGatewayProgram.methods
.updateGatewayAddress(baseArgs)
.accounts({
custodian: minter,
gatewayInfo: gatewayBaseInfo,
authority,
})
.rpc()

console.log(
"Updated Solana gateway with Base..",
Array.from(Buffer.alloc(32, BASE_GATEWAY, "hex"))
)

// Updating with self (SOLANA)
const solanaArgs = {
chain: consts.WH_SOLANA_CHAIN_ID,
address: Array.from(new PublicKey(SOLANA_GATEWAY).toBuffer()),
}

const encodedSolanaChain = Buffer.alloc(2)
encodedSolanaChain.writeUInt16LE(consts.WH_SOLANA_CHAIN_ID)
const gatewaySolanaInfo = PublicKey.findProgramAddressSync(
[Buffer.from("gateway-info"), encodedSolanaChain],
wormholeGatewayProgram.programId
)[0]

await wormholeGatewayProgram.methods
.updateGatewayAddress(solanaArgs)
.accounts({
custodian: minter,
gatewayInfo: gatewaySolanaInfo,
authority,
})
.rpc()

console.log(
"Updated Solana gateway with self (Solana)..",
Array.from(new PublicKey(SOLANA_GATEWAY).toBuffer())
)

console.log("Done initializing programs!")
}

;(async () => {
try {
await run()
} catch (e) {
console.log("Exception called:", e)
}
})()

function loadKey(filename: string): Keypair {
try {
const contents = fs.readFileSync(filename).toString()
const bs = Uint8Array.from(JSON.parse(contents))

return Keypair.fromSecretKey(bs)
} catch {
console.log("Unable to read keypair...", filename)
}
}
Loading