forked from Concordium/concordium-rust-sdk
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathinit-update-contract.rs
151 lines (135 loc) · 5.07 KB
/
init-update-contract.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
#![allow(deprecated)]
//! Basic example that shows how to initialize and update a smart contract.
//!
//! In particular, it uses the "weather" contract which is part of the
//! [icecream example contract](https://github.com/Concordium/concordium-rust-smart-contracts/blob/main/examples/icecream/src/lib.rs).
use anyhow::Context;
use clap::AppSettings;
use concordium_rust_sdk::{
common::{types::TransactionTime, SerdeDeserialize, SerdeSerialize},
endpoints,
smart_contracts::{
common as concordium_std,
common::{Amount, ContractAddress, OwnedContractName, OwnedReceiveName, Serial},
},
types::{
smart_contracts::{ModuleReference, OwnedParameter},
transactions::{send, BlockItem, InitContractPayload, UpdateContractPayload},
AccountInfo, WalletAccount,
},
};
use std::path::PathBuf;
use structopt::*;
use thiserror::Error;
#[derive(StructOpt)]
struct App {
#[structopt(
long = "node",
help = "GRPC interface of the node.",
default_value = "http://localhost:10000"
)]
endpoint: endpoints::Endpoint,
#[structopt(long = "account", help = "Path to the account key file.")]
keys_path: PathBuf,
#[structopt(subcommand, help = "The action you want to perform.")]
action: Action,
}
#[derive(StructOpt)]
enum Action {
#[structopt(about = "Initialize the contract with the provided weather")]
Init {
#[structopt(long, help = "The initial weather.")]
weather: Weather,
#[structopt(
long,
help = "The module reference used for initializing the contract instance."
)]
module_ref: ModuleReference,
},
#[structopt(about = "Update the contract and set the provided weather")]
Update {
#[structopt(long, help = "The new weather.")]
weather: Weather,
#[structopt(long, help = "The contract to update the weather on.")]
address: ContractAddress,
},
}
// The order must match the enum defined in the contract code. Otherwise, the
// serialization will be incorrect.
#[derive(SerdeSerialize, SerdeDeserialize, Serial, StructOpt)]
enum Weather {
Rainy,
Sunny,
}
#[derive(Debug, Error)]
#[error("invalid weather variant; expected \"rainy\" or \"sunny\", but got \"{0}\"")]
struct WeatherError(String);
impl std::str::FromStr for Weather {
type Err = WeatherError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"rainy" => Ok(Weather::Rainy),
"sunny" => Ok(Weather::Sunny),
_ => Err(WeatherError(s.to_owned())),
}
}
}
#[tokio::main(flavor = "multi_thread")]
async fn main() -> anyhow::Result<()> {
let app = {
let app = App::clap().global_setting(AppSettings::ColoredHelp);
let matches = app.get_matches();
App::from_clap(&matches)
};
let mut client = endpoints::Client::connect(app.endpoint, "rpcadmin").await?;
// load account keys and sender address from a file
let keys: WalletAccount =
WalletAccount::from_json_file(app.keys_path).context("Could not parse the keys file.")?;
let consensus_info = client.get_consensus_status().await?;
// Get the initial nonce at the last finalized block.
let acc_info: AccountInfo = client
.get_account_info(&keys.address, &consensus_info.last_finalized_block)
.await?;
let nonce = acc_info.account_nonce;
// set expiry to now + 5min
let expiry: TransactionTime =
TransactionTime::from_seconds((chrono::Utc::now().timestamp() + 300) as u64);
let tx = match app.action {
Action::Init {
weather,
module_ref: mod_ref,
} => {
let param = OwnedParameter::from_serial(&weather)
.expect("Known to not exceed parameter size limit.");
let payload = InitContractPayload {
amount: Amount::zero(),
mod_ref,
init_name: OwnedContractName::new_unchecked("init_weather".to_string()),
param,
};
send::init_contract(&keys, keys.address, nonce, expiry, payload, 10000u64.into())
}
Action::Update { weather, address } => {
let message = OwnedParameter::from_serial(&weather)
.expect("Known to not exceed parameter size limit.");
let payload = UpdateContractPayload {
amount: Amount::zero(),
address,
receive_name: OwnedReceiveName::new_unchecked("weather.set".to_string()),
message,
};
send::update_contract(&keys, keys.address, nonce, expiry, payload, 10000u64.into())
}
};
let item = BlockItem::AccountTransaction(tx);
// submit the transaction to the chain
let transaction_hash = client.send_block_item(&item).await?;
println!(
"Transaction {} submitted (nonce = {}).",
transaction_hash, nonce,
);
let (bh, bs) = client.wait_until_finalized(&transaction_hash).await?;
println!("Transaction finalized in block {}.", bh);
println!("The outcome is {:#?}", bs);
Ok(())
}