Skip to content

Commit cdf99f4

Browse files
jayantkJayant KrishnamurthyJayant Krishnamurthy
authored
Upgrade contract & fix deployment script (#447)
* merge * stuff * gr * config * config * config * config * config * config * config * cleanup * add commands * cleaunp * fix * use u64 Co-authored-by: Jayant Krishnamurthy <jkrishnamurthy@jumptrading.com> Co-authored-by: Jayant Krishnamurthy <jayant@jumpcrypto.com>
1 parent 6833f41 commit cdf99f4

File tree

5 files changed

+121
-56
lines changed

5 files changed

+121
-56
lines changed

cosmwasm/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ First, build the contracts within [the current directory](./):
2121
bash build.sh
2222
```
2323

24-
This command will build and save the Pyth contract in the `artifact` directory.
24+
This command will build and save the Pyth contract in the `artifacts` directory.
2525

2626
Then, to deploy the Pyth contract (`pyth_cosmwasm.wasm`), run the following command in the `tools` directory:
2727

cosmwasm/contracts/pyth/src/contract.rs

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,10 @@ use {
3434
entry_point,
3535
has_coins,
3636
to_binary,
37+
Addr,
3738
Binary,
3839
Coin,
40+
CosmosMsg,
3941
Deps,
4042
DepsMut,
4143
Env,
@@ -46,6 +48,7 @@ use {
4648
Response,
4749
StdResult,
4850
Timestamp,
51+
WasmMsg,
4952
WasmQuery,
5053
},
5154
p2w_sdk::BatchPriceAttestation,
@@ -67,9 +70,19 @@ use {
6770
},
6871
};
6972

73+
/// Migration code that runs once when the contract is upgraded. On upgrade, the migrate
74+
/// function in the *new* code version is run, which allows the new code to update the on-chain
75+
/// state before any of its other functions are invoked.
76+
///
77+
/// After the upgrade is complete, the code in this function can be deleted (and replaced with
78+
/// different code for the next migration).
79+
///
80+
/// Most upgrades won't require any special migration logic. In those cases,
81+
/// this function can safely be implemented as:
82+
/// `Ok(Response::default())`
7083
#[cfg_attr(not(feature = "library"), entry_point)]
7184
pub fn migrate(_deps: DepsMut, _env: Env, _msg: MigrateMsg) -> StdResult<Response> {
72-
Ok(Response::new())
85+
Ok(Response::default())
7386
}
7487

7588
#[cfg_attr(not(feature = "library"), entry_point)]
@@ -182,9 +195,11 @@ fn execute_governance_instruction(
182195
}
183196

184197
let response = match instruction.action {
185-
UpgradeContract { .. } => {
186-
// FIXME: implement this
187-
Err(PythContractError::InvalidGovernancePayload)?
198+
UpgradeContract { code_id } => {
199+
if instruction.target_chain_id == 0 {
200+
Err(PythContractError::InvalidGovernancePayload)?
201+
}
202+
upgrade_contract(&env.contract.address, code_id)?
188203
}
189204
AuthorizeGovernanceDataSourceTransfer { claim_vaa } => {
190205
let parsed_claim_vaa = parse_vaa(deps.branch(), env.block.time.seconds(), &claim_vaa)?;
@@ -286,6 +301,20 @@ fn transfer_governance(
286301
}
287302
}
288303

304+
/// Upgrades the contract at `address` to `new_code_id` (by sending a `Migrate` message). The
305+
/// migration will fail unless this contract is the admin of the contract being upgraded.
306+
/// (Typically, `address` is this contract's address, and the contract is its own admin.)
307+
fn upgrade_contract(address: &Addr, new_code_id: u64) -> StdResult<Response> {
308+
Ok(Response::new()
309+
.add_message(CosmosMsg::Wasm(WasmMsg::Migrate {
310+
contract_addr: address.to_string(),
311+
new_code_id,
312+
msg: to_binary(&MigrateMsg {})?,
313+
}))
314+
.add_attribute("action", "upgrade_contract")
315+
.add_attribute("new_code_id", format!("{new_code_id}")))
316+
}
317+
289318
/// Check that `vaa` is from a valid data source (and hence is a legitimate price update message).
290319
fn verify_vaa_from_data_source(state: &ConfigInfo, vaa: &ParsedVAA) -> StdResult<()> {
291320
let vaa_data_source = PythDataSource {

cosmwasm/contracts/pyth/src/governance.rs

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -51,9 +51,9 @@ impl GovernanceModule {
5151
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema)]
5252
#[repr(u8)]
5353
pub enum GovernanceAction {
54-
UpgradeContract { address: [u8; 20] }, // 0
54+
UpgradeContract { code_id: u64 }, // 0
5555
AuthorizeGovernanceDataSourceTransfer { claim_vaa: Binary }, // 1
56-
SetDataSources { data_sources: Vec<PythDataSource> }, // 2
56+
SetDataSources { data_sources: Vec<PythDataSource> }, // 2
5757
// Set the fee to val * (10 ** expo)
5858
SetFee { val: u64, expo: u64 }, // 3
5959
// Set the default valid period to the provided number of seconds
@@ -92,9 +92,8 @@ impl GovernanceInstruction {
9292

9393
let action: Result<GovernanceAction, String> = match action_type {
9494
0 => {
95-
let mut address: [u8; 20] = [0; 20];
96-
bytes.read_exact(&mut address)?;
97-
Ok(GovernanceAction::UpgradeContract { address })
95+
let code_id = bytes.read_u64::<BigEndian>()?;
96+
Ok(GovernanceAction::UpgradeContract { code_id })
9897
}
9998
1 => {
10099
let mut payload: Vec<u8> = vec![];
@@ -161,10 +160,10 @@ impl GovernanceInstruction {
161160
buf.write_u8(self.module.to_u8())?;
162161

163162
match &self.action {
164-
GovernanceAction::UpgradeContract { address } => {
163+
GovernanceAction::UpgradeContract { code_id } => {
165164
buf.write_u8(0)?;
166165
buf.write_u16::<BigEndian>(self.target_chain_id)?;
167-
buf.write_all(address)?;
166+
buf.write_u64::<BigEndian>(*code_id)?;
168167
}
169168
GovernanceAction::AuthorizeGovernanceDataSourceTransfer { claim_vaa } => {
170169
buf.write_u8(1)?;

cosmwasm/tools/deploy-pyth-bridge.js

Lines changed: 80 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,10 @@ import {
77
import { readFileSync } from "fs";
88
import { Bech32, toHex } from "@cosmjs/encoding";
99
import { zeroPad } from "ethers/lib/utils.js";
10-
import axios from "axios";
1110
import yargs from "yargs";
1211
import { hideBin } from "yargs/helpers";
1312
import assert from "assert";
1413

15-
export const TERRA_GAS_PRICES_URL = "https://fcd.terra.dev/v1/txs/gas_prices";
16-
1714
const argv = yargs(hideBin(process.argv))
1815
.option("network", {
1916
description: "Which network to deploy to",
@@ -64,38 +61,96 @@ const artifact = argv.artifact;
6461
const CONFIG = {
6562
mainnet: {
6663
terraHost: {
67-
URL: "https://lcd.terra.dev",
68-
chainID: "columbus-5",
64+
URL: "https://phoenix-lcd.terra.dev",
65+
chainID: "phoenix-1",
6966
name: "mainnet",
7067
},
71-
wormholeContract: "terra1dq03ugtd40zu9hcgdzrsq6z2z4hwhc9tqk2uy5",
72-
pythEmitterAddress:
73-
"6bb14509a612f01fbbc4cffeebd4bbfb492a86df717ebe92eb6df432a3f00a25",
68+
pyth_config: {
69+
wormhole_contract:
70+
"terra12mrnzvhx3rpej6843uge2yyfppfyd3u9c3uq223q8sl48huz9juqffcnh",
71+
data_sources: [
72+
{
73+
emitter: Buffer.from(
74+
"6bb14509a612f01fbbc4cffeebd4bbfb492a86df717ebe92eb6df432a3f00a25",
75+
"hex"
76+
).toString("base64"),
77+
chain_id: 1,
78+
},
79+
{
80+
emitter: Buffer.from(
81+
"f8cd23c2ab91237730770bbea08d61005cdda0984348f3f6eecb559638c0bba0",
82+
"hex"
83+
).toString("base64"),
84+
chain_id: 26,
85+
},
86+
],
87+
governance_source: {
88+
emitter: Buffer.from(
89+
"5635979a221c34931e32620b9293a463065555ea71fe97cd6237ade875b12e9e",
90+
"hex"
91+
).toString("base64"),
92+
chain_id: 1,
93+
},
94+
governance_source_index: 0,
95+
governance_sequence_number: 0,
96+
chain_id: 18,
97+
valid_time_period_secs: 60,
98+
fee: {
99+
amount: "1",
100+
denom: "uluna",
101+
},
102+
},
74103
},
75104
testnet: {
76105
terraHost: {
77-
URL: "https://bombay-lcd.terra.dev",
78-
chainID: "bombay-12",
106+
URL: "https://pisco-lcd.terra.dev",
107+
chainID: "pisco-1",
79108
name: "testnet",
80109
},
81-
wormholeContract: "terra1pd65m0q9tl3v8znnz5f5ltsfegyzah7g42cx5v",
82-
pythEmitterAddress:
83-
"f346195ac02f37d60d4db8ffa6ef74cb1be3550047543a4a9ee9acf4d78697b0",
110+
pyth_config: {
111+
wormhole_contract:
112+
"terra19nv3xr5lrmmr7egvrk2kqgw4kcn43xrtd5g0mpgwwvhetusk4k7s66jyv0",
113+
data_sources: [
114+
{
115+
emitter: Buffer.from(
116+
"f346195ac02f37d60d4db8ffa6ef74cb1be3550047543a4a9ee9acf4d78697b0",
117+
"hex"
118+
).toString("base64"),
119+
chain_id: 1,
120+
},
121+
{
122+
emitter: Buffer.from(
123+
"a27839d641b07743c0cb5f68c51f8cd31d2c0762bec00dc6fcd25433ef1ab5b6",
124+
"hex"
125+
).toString("base64"),
126+
chain_id: 26,
127+
},
128+
],
129+
governance_source: {
130+
emitter: Buffer.from(
131+
"63278d271099bfd491951b3e648f08b1c71631e4a53674ad43e8f9f98068c385",
132+
"hex"
133+
).toString("base64"),
134+
chain_id: 1,
135+
},
136+
governance_source_index: 0,
137+
governance_sequence_number: 0,
138+
chain_id: 18,
139+
valid_time_period_secs: 60,
140+
fee: {
141+
amount: "1",
142+
denom: "uluna",
143+
},
144+
},
84145
},
85146
};
86147

87148
const terraHost = CONFIG[argv.network].terraHost;
88-
const wormholeContract = CONFIG[argv.network].wormholeContract;
89-
const pythEmitterAddress = CONFIG[argv.network].pythEmitterAddress;
90-
149+
const pythConfig = CONFIG[argv.network].pyth_config;
91150
const lcd = new LCDClient(terraHost);
92151

93152
const feeDenoms = ["uluna"];
94153

95-
const gasPrices = await axios
96-
.get(TERRA_GAS_PRICES_URL)
97-
.then((result) => result.data);
98-
99154
const wallet = lcd.wallet(
100155
new MnemonicKey({
101156
mnemonic: argv.mnemonic,
@@ -124,22 +179,9 @@ if (argv.codeId !== undefined) {
124179
contract_bytes.toString("base64")
125180
);
126181

127-
const feeEstimate = await lcd.tx.estimateFee(
128-
wallet.key.accAddress,
129-
[store_code],
130-
{
131-
feeDenoms,
132-
gasPrices,
133-
}
134-
);
135-
136-
console.log("Deploy fee: ", feeEstimate.amount.toString());
137-
138182
const tx = await wallet.createAndSignTx({
139183
msgs: [store_code],
140184
feeDenoms,
141-
gasPrices,
142-
fee: feeEstimate,
143185
});
144186

145187
const rs = await lcd.tx.broadcast(tx);
@@ -166,7 +208,7 @@ if (argv.codeId !== undefined) {
166208
if (argv.instantiate) {
167209
console.log("Instantiating a contract");
168210

169-
async function instantiate(codeId, inst_msg) {
211+
async function instantiate(codeId, inst_msg, label) {
170212
var address;
171213
await wallet
172214
.createAndSignTx({
@@ -175,7 +217,9 @@ if (argv.instantiate) {
175217
wallet.key.accAddress,
176218
wallet.key.accAddress,
177219
codeId,
178-
inst_msg
220+
inst_msg,
221+
undefined,
222+
label
179223
),
180224
],
181225
})
@@ -199,13 +243,7 @@ if (argv.instantiate) {
199243
return address;
200244
}
201245

202-
const pythChain = 1;
203-
204-
const contractAddress = await instantiate(codeId, {
205-
wormhole_contract: wormholeContract,
206-
pyth_emitter: Buffer.from(pythEmitterAddress, "hex").toString("base64"),
207-
pyth_emitter_chain: pythChain,
208-
});
246+
const contractAddress = await instantiate(codeId, pythConfig, "pyth");
209247

210248
console.log(`Deployed Pyth contract at ${contractAddress}`);
211249
}
@@ -233,7 +271,6 @@ if (argv.migrate) {
233271
),
234272
],
235273
feeDenoms,
236-
gasPrices,
237274
});
238275

239276
const rs = await lcd.tx.broadcast(tx);

cosmwasm/tools/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
"main": "deploy.js",
66
"type": "module",
77
"scripts": {
8-
"test": "echo \"Error: no test specified\" && exit 1"
8+
"deploy-pyth": "node deploy-pyth-bridge.js"
99
},
1010
"author": "",
1111
"license": "ISC",

0 commit comments

Comments
 (0)