contract.rs 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442
  1. use cosmwasm_std::{
  2. has_coins,
  3. log,
  4. to_binary,
  5. Api,
  6. BankMsg,
  7. Binary,
  8. Coin,
  9. CosmosMsg,
  10. Env,
  11. Extern,
  12. HandleResponse,
  13. HumanAddr,
  14. InitResponse,
  15. Querier,
  16. StdError,
  17. StdResult,
  18. Storage,
  19. };
  20. use crate::{
  21. byte_utils::{
  22. extend_address_to_32,
  23. ByteUtils,
  24. },
  25. error::ContractError,
  26. msg::{
  27. GetAddressHexResponse,
  28. GetStateResponse,
  29. GuardianSetInfoResponse,
  30. HandleMsg,
  31. InitMsg,
  32. QueryMsg,
  33. },
  34. state::{
  35. config,
  36. config_read,
  37. guardian_set_get,
  38. guardian_set_set,
  39. sequence_read,
  40. sequence_set,
  41. vaa_archive_add,
  42. vaa_archive_check,
  43. ConfigInfo,
  44. GovernancePacket,
  45. GuardianAddress,
  46. GuardianSetInfo,
  47. GuardianSetUpgrade,
  48. ParsedVAA,
  49. SetFee,
  50. TransferFee,
  51. },
  52. };
  53. use k256::{
  54. ecdsa::{
  55. recoverable::{
  56. Id as RecoverableId,
  57. Signature as RecoverableSignature,
  58. },
  59. Signature,
  60. VerifyKey,
  61. },
  62. EncodedPoint,
  63. };
  64. use sha3::{
  65. Digest,
  66. Keccak256,
  67. };
  68. use generic_array::GenericArray;
  69. use std::convert::TryFrom;
  70. // Chain ID of Terra
  71. const CHAIN_ID: u16 = 3;
  72. // Lock assets fee amount and denomination
  73. const FEE_AMOUNT: u128 = 10000;
  74. pub const FEE_DENOMINATION: &str = "uluna";
  75. pub fn init<S: Storage, A: Api, Q: Querier>(
  76. deps: &mut Extern<S, A, Q>,
  77. _env: Env,
  78. msg: InitMsg,
  79. ) -> StdResult<InitResponse> {
  80. // Save general wormhole info
  81. let state = ConfigInfo {
  82. gov_chain: msg.gov_chain,
  83. gov_address: msg.gov_address.as_slice().to_vec(),
  84. guardian_set_index: 0,
  85. guardian_set_expirity: msg.guardian_set_expirity,
  86. fee: Coin::new(FEE_AMOUNT, FEE_DENOMINATION), // 0.01 Luna (or 10000 uluna) fee by default
  87. };
  88. config(&mut deps.storage).save(&state)?;
  89. // Add initial guardian set to storage
  90. guardian_set_set(
  91. &mut deps.storage,
  92. state.guardian_set_index,
  93. &msg.initial_guardian_set,
  94. )?;
  95. Ok(InitResponse::default())
  96. }
  97. pub fn handle<S: Storage, A: Api, Q: Querier>(
  98. deps: &mut Extern<S, A, Q>,
  99. env: Env,
  100. msg: HandleMsg,
  101. ) -> StdResult<HandleResponse> {
  102. match msg {
  103. HandleMsg::PostMessage { message, nonce } => {
  104. handle_post_message(deps, env, &message.as_slice(), nonce)
  105. }
  106. HandleMsg::SubmitVAA { vaa } => handle_submit_vaa(deps, env, vaa.as_slice()),
  107. }
  108. }
  109. /// Process VAA message signed by quardians
  110. fn handle_submit_vaa<S: Storage, A: Api, Q: Querier>(
  111. deps: &mut Extern<S, A, Q>,
  112. env: Env,
  113. data: &[u8],
  114. ) -> StdResult<HandleResponse> {
  115. let state = config_read(&deps.storage).load()?;
  116. let vaa = parse_and_verify_vaa(&deps.storage, data, env.block.time)?;
  117. vaa_archive_add(&mut deps.storage, vaa.hash.as_slice())?;
  118. if state.gov_chain == vaa.emitter_chain && state.gov_address == vaa.emitter_address {
  119. if state.guardian_set_index != vaa.guardian_set_index {
  120. return Err(StdError::generic_err(
  121. "governance VAAs must be signed by the current guardian set",
  122. ));
  123. }
  124. return handle_governance_payload(deps, env, &vaa.payload);
  125. }
  126. ContractError::InvalidVAAAction.std_err()
  127. }
  128. fn handle_governance_payload<S: Storage, A: Api, Q: Querier>(
  129. deps: &mut Extern<S, A, Q>,
  130. env: Env,
  131. data: &Vec<u8>,
  132. ) -> StdResult<HandleResponse> {
  133. let gov_packet = GovernancePacket::deserialize(&data)?;
  134. let module = String::from_utf8(gov_packet.module).unwrap();
  135. let module: String = module.chars().filter(|c| c != &'\0').collect();
  136. if module != "Core" {
  137. return Err(StdError::generic_err("this is not a valid module"));
  138. }
  139. if gov_packet.chain != 0 && gov_packet.chain != CHAIN_ID {
  140. return Err(StdError::generic_err(
  141. "the governance VAA is for another chain",
  142. ));
  143. }
  144. match gov_packet.action {
  145. // 1 is reserved for upgrade / migration
  146. 2u8 => vaa_update_guardian_set(deps, env, &gov_packet.payload),
  147. 3u8 => handle_set_fee(deps, env, &gov_packet.payload),
  148. 4u8 => handle_transfer_fee(deps, env, &gov_packet.payload),
  149. _ => ContractError::InvalidVAAAction.std_err(),
  150. }
  151. }
  152. /// Parses raw VAA data into a struct and verifies whether it contains sufficient signatures of an
  153. /// active guardian set i.e. is valid according to Wormhole consensus rules
  154. fn parse_and_verify_vaa<S: Storage>(
  155. storage: &S,
  156. data: &[u8],
  157. block_time: u64,
  158. ) -> StdResult<ParsedVAA> {
  159. let vaa = ParsedVAA::deserialize(data)?;
  160. if vaa.version != 1 {
  161. return ContractError::InvalidVersion.std_err();
  162. }
  163. // Check if VAA with this hash was already accepted
  164. if vaa_archive_check(storage, vaa.hash.as_slice()) {
  165. return ContractError::VaaAlreadyExecuted.std_err();
  166. }
  167. // Load and check guardian set
  168. let guardian_set = guardian_set_get(storage, vaa.guardian_set_index);
  169. let guardian_set: GuardianSetInfo =
  170. guardian_set.or_else(|_| ContractError::InvalidGuardianSetIndex.std_err())?;
  171. if guardian_set.expiration_time != 0 && guardian_set.expiration_time < block_time {
  172. return ContractError::GuardianSetExpired.std_err();
  173. }
  174. if (vaa.len_signers as usize) < guardian_set.quorum() {
  175. return ContractError::NoQuorum.std_err();
  176. }
  177. // Verify guardian signatures
  178. let mut last_index: i32 = -1;
  179. let mut pos = ParsedVAA::HEADER_LEN;
  180. for _ in 0..vaa.len_signers {
  181. if pos + ParsedVAA::SIGNATURE_LEN > data.len() {
  182. return ContractError::InvalidVAA.std_err();
  183. }
  184. let index = data.get_u8(pos) as i32;
  185. if index <= last_index {
  186. return ContractError::WrongGuardianIndexOrder.std_err();
  187. }
  188. last_index = index;
  189. let signature = Signature::try_from(
  190. &data[pos + ParsedVAA::SIG_DATA_POS
  191. ..pos + ParsedVAA::SIG_DATA_POS + ParsedVAA::SIG_DATA_LEN],
  192. )
  193. .or_else(|_| ContractError::CannotDecodeSignature.std_err())?;
  194. let id = RecoverableId::new(data.get_u8(pos + ParsedVAA::SIG_RECOVERY_POS))
  195. .or_else(|_| ContractError::CannotDecodeSignature.std_err())?;
  196. let recoverable_signature = RecoverableSignature::new(&signature, id)
  197. .or_else(|_| ContractError::CannotDecodeSignature.std_err())?;
  198. let verify_key = recoverable_signature
  199. .recover_verify_key_from_digest_bytes(GenericArray::from_slice(vaa.hash.as_slice()))
  200. .or_else(|_| ContractError::CannotRecoverKey.std_err())?;
  201. let index = index as usize;
  202. if index >= guardian_set.addresses.len() {
  203. return ContractError::TooManySignatures.std_err();
  204. }
  205. if !keys_equal(&verify_key, &guardian_set.addresses[index]) {
  206. return ContractError::GuardianSignatureError.std_err();
  207. }
  208. pos += ParsedVAA::SIGNATURE_LEN;
  209. }
  210. Ok(vaa)
  211. }
  212. fn vaa_update_guardian_set<S: Storage, A: Api, Q: Querier>(
  213. deps: &mut Extern<S, A, Q>,
  214. env: Env,
  215. data: &Vec<u8>,
  216. ) -> StdResult<HandleResponse> {
  217. /* Payload format
  218. 0 uint32 new_index
  219. 4 uint8 len(keys)
  220. 5 [][20]uint8 guardian addresses
  221. */
  222. let mut state = config_read(&deps.storage).load()?;
  223. let GuardianSetUpgrade {
  224. new_guardian_set_index,
  225. new_guardian_set,
  226. } = GuardianSetUpgrade::deserialize(&data)?;
  227. if new_guardian_set_index != state.guardian_set_index + 1 {
  228. return ContractError::GuardianSetIndexIncreaseError.std_err();
  229. }
  230. let old_guardian_set_index = state.guardian_set_index;
  231. state.guardian_set_index = new_guardian_set_index;
  232. guardian_set_set(
  233. &mut deps.storage,
  234. state.guardian_set_index,
  235. &new_guardian_set,
  236. )?;
  237. config(&mut deps.storage).save(&state)?;
  238. let mut old_guardian_set = guardian_set_get(&deps.storage, old_guardian_set_index)?;
  239. old_guardian_set.expiration_time = env.block.time + state.guardian_set_expirity;
  240. guardian_set_set(&mut deps.storage, old_guardian_set_index, &old_guardian_set)?;
  241. Ok(HandleResponse {
  242. messages: vec![],
  243. log: vec![
  244. log("action", "guardian_set_change"),
  245. log("old", old_guardian_set_index),
  246. log("new", state.guardian_set_index),
  247. ],
  248. data: None,
  249. })
  250. }
  251. pub fn handle_set_fee<S: Storage, A: Api, Q: Querier>(
  252. deps: &mut Extern<S, A, Q>,
  253. env: Env,
  254. data: &Vec<u8>,
  255. ) -> StdResult<HandleResponse> {
  256. let set_fee_msg = SetFee::deserialize(&data)?;
  257. // Save new fees
  258. let mut state = config_read(&mut deps.storage).load()?;
  259. state.fee = set_fee_msg.fee;
  260. config(&mut deps.storage).save(&state)?;
  261. Ok(HandleResponse {
  262. messages: vec![],
  263. log: vec![
  264. log("action", "fee_change"),
  265. log("new_fee.amount", state.fee.amount),
  266. log("new_fee.denom", state.fee.denom),
  267. ],
  268. data: None,
  269. })
  270. }
  271. pub fn handle_transfer_fee<S: Storage, A: Api, Q: Querier>(
  272. deps: &mut Extern<S, A, Q>,
  273. env: Env,
  274. data: &Vec<u8>,
  275. ) -> StdResult<HandleResponse> {
  276. let transfer_msg = TransferFee::deserialize(&data)?;
  277. Ok(HandleResponse {
  278. messages: vec![CosmosMsg::Bank(BankMsg::Send {
  279. from_address: env.contract.address,
  280. to_address: deps.api.human_address(&transfer_msg.recipient)?,
  281. amount: vec![transfer_msg.amount],
  282. })],
  283. log: vec![],
  284. data: None,
  285. })
  286. }
  287. fn handle_post_message<S: Storage, A: Api, Q: Querier>(
  288. deps: &mut Extern<S, A, Q>,
  289. env: Env,
  290. message: &[u8],
  291. nonce: u32,
  292. ) -> StdResult<HandleResponse> {
  293. let state = config_read(&deps.storage).load()?;
  294. let fee = state.fee;
  295. // Check fee
  296. if !has_coins(env.message.sent_funds.as_ref(), &fee) {
  297. return ContractError::FeeTooLow.std_err();
  298. }
  299. let emitter = extend_address_to_32(&deps.api.canonical_address(&env.message.sender)?);
  300. let sequence = sequence_read(&deps.storage, emitter.as_slice());
  301. sequence_set(&mut deps.storage, emitter.as_slice(), sequence + 1)?;
  302. Ok(HandleResponse {
  303. messages: vec![],
  304. log: vec![
  305. log("message.message", hex::encode(message)),
  306. log("message.sender", hex::encode(emitter)),
  307. log("message.chain_id", CHAIN_ID),
  308. log("message.nonce", nonce),
  309. log("message.sequence", sequence),
  310. log("message.block_time", env.block.time),
  311. ],
  312. data: None,
  313. })
  314. }
  315. pub fn query<S: Storage, A: Api, Q: Querier>(
  316. deps: &Extern<S, A, Q>,
  317. msg: QueryMsg,
  318. ) -> StdResult<Binary> {
  319. match msg {
  320. QueryMsg::GuardianSetInfo {} => to_binary(&query_guardian_set_info(deps)?),
  321. QueryMsg::VerifyVAA { vaa, block_time } => to_binary(&query_parse_and_verify_vaa(
  322. deps,
  323. &vaa.as_slice(),
  324. block_time,
  325. )?),
  326. QueryMsg::GetState {} => to_binary(&query_state(deps)?),
  327. QueryMsg::QueryAddressHex { address } => to_binary(&query_address_hex(deps, &address)?),
  328. }
  329. }
  330. pub fn query_guardian_set_info<S: Storage, A: Api, Q: Querier>(
  331. deps: &Extern<S, A, Q>,
  332. ) -> StdResult<GuardianSetInfoResponse> {
  333. let state = config_read(&deps.storage).load()?;
  334. let guardian_set = guardian_set_get(&deps.storage, state.guardian_set_index)?;
  335. let res = GuardianSetInfoResponse {
  336. guardian_set_index: state.guardian_set_index,
  337. addresses: guardian_set.addresses,
  338. };
  339. Ok(res)
  340. }
  341. pub fn query_parse_and_verify_vaa<S: Storage, A: Api, Q: Querier>(
  342. deps: &Extern<S, A, Q>,
  343. data: &[u8],
  344. block_time: u64,
  345. ) -> StdResult<ParsedVAA> {
  346. parse_and_verify_vaa(&deps.storage, data, block_time)
  347. }
  348. // returns the hex of the 32 byte address we use for some address on this chain
  349. pub fn query_address_hex<S: Storage, A: Api, Q: Querier>(
  350. deps: &Extern<S, A, Q>,
  351. address: &HumanAddr,
  352. ) -> StdResult<GetAddressHexResponse> {
  353. Ok(GetAddressHexResponse {
  354. hex: hex::encode(extend_address_to_32(&deps.api.canonical_address(&address)?)),
  355. })
  356. }
  357. pub fn query_state<S: Storage, A: Api, Q: Querier>(
  358. deps: &Extern<S, A, Q>,
  359. ) -> StdResult<GetStateResponse> {
  360. let state = config_read(&deps.storage).load()?;
  361. let res = GetStateResponse { fee: state.fee };
  362. Ok(res)
  363. }
  364. fn keys_equal(a: &VerifyKey, b: &GuardianAddress) -> bool {
  365. let mut hasher = Keccak256::new();
  366. let point: EncodedPoint = EncodedPoint::from(a);
  367. let point = point.decompress();
  368. if bool::from(point.is_none()) {
  369. return false;
  370. }
  371. let point = point.unwrap();
  372. hasher.update(&point.as_bytes()[1..]);
  373. let a = &hasher.finalize()[12..];
  374. let b = &b.bytes;
  375. if a.len() != b.len() {
  376. return false;
  377. }
  378. for (ai, bi) in a.iter().zip(b.as_slice().iter()) {
  379. if ai != bi {
  380. return false;
  381. }
  382. }
  383. true
  384. }