From f0872f8ac6ed6ca926d18e864829c3c54cfa0ea9 Mon Sep 17 00:00:00 2001 From: Karl Kempe Date: Fri, 13 May 2022 14:22:49 +0000 Subject: [PATCH] Add sale_sealed (need to add test) --- .../icco-contributor/src/contract.rs | 27 +- terra/contracts/icco-contributor/src/error.rs | 9 + .../contracts/icco-contributor/src/execute.rs | 147 +- terra/contracts/icco-contributor/src/msg.rs | 4 +- terra/contracts/icco-contributor/src/query.rs | 2 +- terra/contracts/icco-contributor/src/state.rs | 27 +- .../icco-contributor/src/testing/tests.rs | 17 +- terra/packages/icco/src/common.rs | 86 +- terra/packages/icco/src/error.rs | 3 + terra/scripts/helpers.ts | 67 +- terra/scripts/package-lock.json | 1593 +++++++++++++++++ terra/scripts/package.json | 3 + terra/scripts/tests/README.md | 36 +- terra/scripts/tests/contributor.ts | 1059 +++++++++-- terra/scripts/tests/lib.ts | 298 +++ 15 files changed, 3090 insertions(+), 288 deletions(-) create mode 100644 terra/scripts/tests/lib.ts diff --git a/terra/contracts/icco-contributor/src/contract.rs b/terra/contracts/icco-contributor/src/contract.rs index d4f5ce65..d3719628 100644 --- a/terra/contracts/icco-contributor/src/contract.rs +++ b/terra/contracts/icco-contributor/src/contract.rs @@ -1,8 +1,10 @@ use cosmwasm_std::{ entry_point, to_binary, Binary, Deps, DepsMut, Env, MessageInfo, Reply, Response, StdResult, }; +use icco::common::CHAIN_ID; use crate::{ + error::ContributorError, execute::{ attest_contributions, claim_allocation, claim_refund, contribute, init_sale, sale_aborted, sale_sealed, @@ -30,16 +32,23 @@ pub fn instantiate( ) -> StdResult { let wormhole = deps.api.addr_validate(msg.wormhole.as_str())?; let token_bridge = deps.api.addr_validate(msg.token_bridge.as_str())?; - let cfg = Config { - wormhole, - token_bridge, - conductor_chain: msg.conductor_chain, - conductor_address: msg.conductor_address.into(), - owner: info.sender, - }; - CONFIG.save(deps.storage, &cfg)?; - Ok(Response::default()) + // we know there is no terra conductor existing. So prevent user + // from instantiating with one defined + match msg.conductor_chain { + CHAIN_ID => return ContributorError::UnsupportedConductor.std_err(), + _ => { + let cfg = Config { + wormhole, + token_bridge, + conductor_chain: msg.conductor_chain, + conductor_address: msg.conductor_address.into(), + owner: info.sender, + }; + CONFIG.save(deps.storage, &cfg)?; + Ok(Response::default()) + } + } } // When CW20 transfers complete, we need to verify the actual amount that is being transferred out diff --git a/terra/contracts/icco-contributor/src/error.rs b/terra/contracts/icco-contributor/src/error.rs index 1f8b7e73..202470c0 100644 --- a/terra/contracts/icco-contributor/src/error.rs +++ b/terra/contracts/icco-contributor/src/error.rs @@ -48,15 +48,24 @@ pub enum ContributorError { #[error("SaleEnded")] SaleEnded, + #[error("SaleNonexistent")] + SaleNonexistent, + #[error("SaleNotFinished")] SaleNotFinished, #[error("SaleNotStarted")] SaleNotStarted, + #[error("SaleStillActive")] + SaleStillActive, + #[error("TooManyAcceptedTokens")] TooManyAcceptedTokens, + #[error("UnsupportedConductor")] + UnsupportedConductor, + #[error("WrongBuyerStatus")] WrongBuyerStatus, diff --git a/terra/contracts/icco-contributor/src/execute.rs b/terra/contracts/icco-contributor/src/execute.rs index b9f53c3a..b3370d83 100644 --- a/terra/contracts/icco-contributor/src/execute.rs +++ b/terra/contracts/icco-contributor/src/execute.rs @@ -1,11 +1,11 @@ use cosmwasm_std::{ - to_binary, Addr, Binary, CosmosMsg, Deps, DepsMut, Env, MessageInfo, QuerierWrapper, - QueryRequest, Response, StdError, StdResult, Storage, Uint128, WasmMsg, WasmQuery, + to_binary, Addr, Binary, Coin, CosmosMsg, Deps, DepsMut, Env, MessageInfo, QuerierWrapper, + QueryRequest, Response, StdError, StdResult, Uint128, Uint256, WasmMsg, WasmQuery, }; -use cw20::Cw20ExecuteMsg; +use cw20::{Cw20ExecuteMsg, Cw20QueryMsg, TokenInfoResponse}; use serde::de::DeserializeOwned; use terraswap::{ - asset::AssetInfo, + asset::{Asset, AssetInfo}, querier::{query_balance, query_token_balance}, }; @@ -17,16 +17,20 @@ use wormhole::{ state::ParsedVAA, }; -use icco::common::{ - make_asset_info, ContributionsSealed, SaleAborted, SaleInit, SaleSealed, SaleStatus, CHAIN_ID, +use icco::{ + common::{ + make_asset_info, to_uint128, AssetAllocation, ContributionsSealed, SaleAborted, SaleInit, + SaleSealed, SaleStatus, CHAIN_ID, + }, + error::CommonError, }; use crate::{ error::ContributorError, msg::ExecuteMsg, state::{ - is_sale_active, sale_asset_indices, update_buyer_contribution, AssetKey, BuyerStatus, - PendingContributeToken, TokenIndexKey, ACCEPTED_ASSETS, ASSET_INDICES, CONFIG, + sale_asset_indices, throw_if_active, throw_if_inactive, update_buyer_contribution, + BuyerStatus, PendingContributeToken, TokenIndexKey, ACCEPTED_ASSETS, ASSET_INDICES, CONFIG, PENDING_CONTRIBUTE_TOKEN, SALES, SALE_STATUSES, SALE_TIMES, TOTAL_ALLOCATIONS, TOTAL_CONTRIBUTIONS, }, @@ -44,7 +48,7 @@ pub fn init_sale( let payload = parse_and_verify_vaa(deps.as_ref(), &env, signed_vaa)?; let sale_id = SaleInit::get_sale_id(&payload)?; - if is_sale_active(deps.storage, sale_id) { + if let Ok(_) = SALE_STATUSES.load(deps.storage, sale_id) { return ContributorError::SaleAlreadyExists.std_err(); } @@ -99,7 +103,6 @@ pub fn init_sale( // store other things associated with accepted tokens TOTAL_CONTRIBUTIONS.save(deps.storage, token_key.clone(), &Uint128::zero())?; - TOTAL_ALLOCATIONS.save(deps.storage, token_key, &Uint128::zero())?; } let sale = &sale_init.core; @@ -123,9 +126,7 @@ pub fn contribute( token_index: u8, amount: Uint128, ) -> StdResult { - if !is_sale_active(deps.storage, sale_id) { - return ContributorError::SaleEnded.std_err(); - } + throw_if_inactive(deps.storage, sale_id)?; let times = SALE_TIMES.load(deps.storage, sale_id)?; let now = env.block.time.seconds(); @@ -158,15 +159,19 @@ pub fn attest_contributions( _info: MessageInfo, sale_id: &[u8], ) -> StdResult { - if !is_sale_active(deps.storage, sale_id) { - return ContributorError::SaleEnded.std_err(); - } + throw_if_inactive(deps.storage, sale_id)?; let times = SALE_TIMES.load(deps.storage, sale_id)?; if env.block.time.seconds() <= times.end { return ContributorError::SaleNotFinished.std_err(); } + // Do we care if the orchestrator can attest contributions multiple times? + // The conductor can only collect contributions once per chain, so there + // is no need to add a protection against attesting more than once. + // If we want to add a protection, we can cache the serialized payload + // and check if this is already in storage per sale_id. + let asset_indices = sale_asset_indices(deps.storage, sale_id); let mut contribution_sealed = ContributionsSealed::new(sale_id, CHAIN_ID, asset_indices.len()); @@ -181,7 +186,7 @@ pub fn attest_contributions( let cfg = CONFIG.load(deps.storage)?; Ok(Response::new() - .add_message(execute_contract( + .add_message(execute_contract_without_funds( &cfg.wormhole, to_binary(&WormholeExecuteMsg::PostMessage { message: Binary::from(serialized), @@ -201,12 +206,9 @@ pub fn sale_sealed( let payload = parse_and_verify_vaa(deps.as_ref(), &env, signed_vaa)?; let sale_id = SaleSealed::get_sale_id(&payload)?; - let sale = match is_sale_active(deps.storage, sale_id) { - true => SALES.load(deps.storage, sale_id)?, - _ => { - return ContributorError::SaleEnded.std_err(); - } - }; + throw_if_inactive(deps.storage, sale_id)?; + + let sale = SALES.load(deps.storage, sale_id)?; // sale token handling let asset_info = match sale.token_chain { @@ -221,17 +223,27 @@ pub fn sale_sealed( } }; - let balance = match asset_info { + let (balance, token_decimals) = match asset_info { AssetInfo::NativeToken { denom } => { // this should never happen, but... - query_balance(&deps.querier, env.contract.address, denom)? + ( + query_balance(&deps.querier, env.contract.address, denom)?, + 6u8, + ) + } + AssetInfo::Token { contract_addr } => { + let contract_addr = Addr::unchecked(contract_addr); + let token_info: TokenInfoResponse = query_contract( + &deps.querier, + &contract_addr, + to_binary(&Cw20QueryMsg::TokenInfo {})?, + )?; + + let balance = query_token_balance(&deps.querier, contract_addr, env.contract.address)?; + (balance, token_info.decimals) } - AssetInfo::Token { contract_addr } => query_token_balance( - &deps.querier, - Addr::unchecked(contract_addr), - env.contract.address, - )?, }; + // save some work if we don't have any of the sale tokens if balance == Uint128::zero() { return ContributorError::InsufficientSaleTokens.std_err(); @@ -243,10 +255,14 @@ pub fn sale_sealed( let parsed_allocations = SaleSealed::deserialize_allocations_safely(&payload, sale.num_accepted, &asset_indices)?; - // sum total allocations and check against balance in the contract + // Sum total allocations and check against balance in the contract. + // Keep in mind, these are Uint256. Need to adjust this down to Uint128 let total_allocations = parsed_allocations .iter() - .fold(Uint128::zero(), |total, (_, next)| total + next.allocated); + .fold(Uint256::zero(), |total, (_, next)| total + next.allocated); + + // need to adjust total_allocations based on decimal difference + let total_allocations = sale.adjust_token_amount(total_allocations, token_decimals)?; if balance < total_allocations { return ContributorError::InsufficientSaleTokens.std_err(); @@ -258,19 +274,51 @@ pub fn sale_sealed( // transfer contributions to conductor let cfg = CONFIG.load(deps.storage)?; if cfg.conductor_chain == CHAIN_ID { - // lol - } else { - for &token_index in asset_indices.iter() { - // do token bridge transfers here - } + return ContributorError::UnsupportedConductor.std_err(); + } + + let mut token_bridge_msgs: Vec = Vec::with_capacity(sale.num_accepted as usize); + for &token_index in asset_indices.iter() { + // bridge assets to conductor + let amount = TOTAL_CONTRIBUTIONS.load(deps.storage, (sale_id, token_index.into()))?; + let asset = Asset { + info: ACCEPTED_ASSETS.load(deps.storage, (sale_id, token_index.into()))?, + amount, + }; + + token_bridge_msgs.push(execute_contract_without_funds( + &cfg.token_bridge, + to_binary(&TokenBridgeExecuteMsg::InitiateTransfer { + asset, + recipient_chain: cfg.conductor_chain, + recipient: Binary::from(cfg.conductor_address.clone()), + fee: Uint128::zero(), // does this matter? + nonce: WORMHOLE_NONCE, + })?, + )); } // now update TOTAL_ALLOCATIONS (fix to use AssetAllocation) for (token_index, allocation) in parsed_allocations.iter() { - //TOTAL_ALLOCATIONS.save(deps.storage, (sale_id, token_index.into()), ) + // adjust values from uint256 to uint128 + let allocated = sale.adjust_token_amount(allocation.allocated, token_decimals)?; + let excess_contributed = match to_uint128(allocation.excess_contributed) { + Some(value) => value, + None => return CommonError::AmountExceedsUint128Max.std_err(), + }; + + TOTAL_ALLOCATIONS.save( + deps.storage, + (sale_id, (*token_index).into()), + &AssetAllocation { + allocated, + excess_contributed, + }, + )?; } Ok(Response::new() + .add_messages(token_bridge_msgs) .add_attribute("action", "sale_sealed") .add_attribute("sale_id", Binary::from(sale_id).to_base64()) .add_attribute("total_allocations", total_allocations.to_string())) @@ -283,7 +331,7 @@ pub fn claim_allocation( sale_id: &Binary, token_index: u8, ) -> StdResult { - // TODO devs do something + throw_if_active(deps.storage, sale_id)?; Ok(Response::new().add_attribute("action", "claim_allocation")) } @@ -297,9 +345,7 @@ pub fn sale_aborted( let payload = parse_and_verify_vaa(deps.as_ref(), &env, signed_vaa)?; let sale_id = SaleAborted::get_sale_id(&payload)?; - if !is_sale_active(deps.storage, sale_id) { - return ContributorError::SaleEnded.std_err(); - }; + throw_if_inactive(deps.storage, sale_id)?; SALE_STATUSES.save(deps.storage, sale_id, &SaleStatus::Aborted)?; @@ -315,7 +361,7 @@ pub fn claim_refund( sale_id: &Binary, token_index: u8, ) -> StdResult { - // TODO devs do something + throw_if_active(deps.storage, sale_id)?; Ok(Response::new().add_attribute("action", "claim_refund")) } @@ -417,7 +463,7 @@ fn contribute_token( )?; Ok(Response::new() - .add_message(execute_contract( + .add_message(execute_contract_without_funds( &contract_addr, to_binary(&Cw20ExecuteMsg::TransferFrom { owner: info.sender.to_string(), @@ -425,7 +471,7 @@ fn contribute_token( amount, })?, )) - .add_message(execute_contract( + .add_message(execute_contract_without_funds( &env.contract.address, to_binary(&ExecuteMsg::EscrowUserContributionHook)?, )) @@ -490,8 +536,17 @@ fn query_contract( })) } +// assume only one coin for funds +fn execute_contract_with_funds(contract: &Addr, msg: Binary, funds: Coin) -> CosmosMsg { + CosmosMsg::Wasm(WasmMsg::Execute { + contract_addr: contract.to_string(), + funds: vec![funds], + msg, + }) +} + // no need for funds -fn execute_contract(contract: &Addr, msg: Binary) -> CosmosMsg { +fn execute_contract_without_funds(contract: &Addr, msg: Binary) -> CosmosMsg { CosmosMsg::Wasm(WasmMsg::Execute { contract_addr: contract.to_string(), funds: vec![], diff --git a/terra/contracts/icco-contributor/src/msg.rs b/terra/contracts/icco-contributor/src/msg.rs index 2f2f2a01..51b56533 100644 --- a/terra/contracts/icco-contributor/src/msg.rs +++ b/terra/contracts/icco-contributor/src/msg.rs @@ -3,7 +3,7 @@ use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use terraswap::asset::AssetInfo; -use icco::common::{SaleCore, SaleStatus, SaleTimes}; +use icco::common::{AssetAllocation, SaleCore, SaleStatus, SaleTimes}; use crate::state::BuyerStatus; @@ -136,7 +136,7 @@ pub struct TotalContributionResponse { pub struct TotalAllocationResponse { pub id: Vec, pub token_index: u8, - pub amount: Uint128, + pub allocation: AssetAllocation, } #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] diff --git a/terra/contracts/icco-contributor/src/query.rs b/terra/contracts/icco-contributor/src/query.rs index a4fefa26..4f091eb6 100644 --- a/terra/contracts/icco-contributor/src/query.rs +++ b/terra/contracts/icco-contributor/src/query.rs @@ -60,7 +60,7 @@ pub fn query_total_allocation( Ok(TotalAllocationResponse { id: sale_id.to_vec(), token_index, - amount: TOTAL_ALLOCATIONS.load(deps.storage, (sale_id, token_index.into()))?, + allocation: TOTAL_ALLOCATIONS.load(deps.storage, (sale_id, token_index.into()))?, }) } diff --git a/terra/contracts/icco-contributor/src/state.rs b/terra/contracts/icco-contributor/src/state.rs index 37248f5d..566c6820 100644 --- a/terra/contracts/icco-contributor/src/state.rs +++ b/terra/contracts/icco-contributor/src/state.rs @@ -4,7 +4,7 @@ use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use terraswap::asset::AssetInfo; -use icco::common::{SaleCore, SaleStatus, SaleTimes}; +use icco::common::{AssetAllocation, SaleCore, SaleStatus, SaleTimes}; use crate::error::ContributorError; @@ -73,7 +73,7 @@ pub const SALE_STATUSES: Map = Map::new("sale_statuses"); pub const SALE_TIMES: Map = Map::new("sale_times"); pub const ACCEPTED_ASSETS: Map = Map::new("accepted_assets"); pub const TOTAL_CONTRIBUTIONS: Map = Map::new("total_contributions"); -pub const TOTAL_ALLOCATIONS: Map = Map::new("total_allocations"); +pub const TOTAL_ALLOCATIONS: Map = Map::new("total_allocations"); // per buyer pub const BUYER_STATUSES: Map = Map::new("buyer_statuses"); @@ -175,10 +175,27 @@ pub fn refund_is_claimed( ) } -pub fn is_sale_active(storage: &dyn Storage, sale_id: &[u8]) -> bool { +pub fn throw_if_active(storage: &dyn Storage, sale_id: &[u8]) -> StdResult<()> { match SALE_STATUSES.load(storage, sale_id) { - Ok(status) => status == SaleStatus::Active, - Err(_) => false, + Ok(active) => { + if active == SaleStatus::Active { + return ContributorError::SaleStillActive.std_err(); + } + Ok(()) + } + Err(_) => return ContributorError::SaleNonexistent.std_err(), + } +} + +pub fn throw_if_inactive(storage: &dyn Storage, sale_id: &[u8]) -> StdResult<()> { + match SALE_STATUSES.load(storage, sale_id) { + Ok(active) => { + if active != SaleStatus::Active { + return ContributorError::SaleEnded.std_err(); + } + Ok(()) + } + Err(_) => return ContributorError::SaleNonexistent.std_err(), } } diff --git a/terra/contracts/icco-contributor/src/testing/tests.rs b/terra/contracts/icco-contributor/src/testing/tests.rs index 7efd08ef..268fa08c 100644 --- a/terra/contracts/icco-contributor/src/testing/tests.rs +++ b/terra/contracts/icco-contributor/src/testing/tests.rs @@ -208,7 +208,7 @@ fn init_sale() -> StdResult<()> { 3057543273fcb20100000001000000020002000000000000000000000000f19a\ 2a01b70519f67adb309a994ec8c69a967e8b0000000000000003010100000000\ 0000000000000000000000000000000000000000000000000000000200000000\ - 000000000000000083752ecafebf4707258dedffbd9c7443148169db00020000\ + 000000000000000083752ecafebf4707258dedffbd9c7443148169db0002120000\ 000000000000000000000000000000000000000000000de0b6b3a76400000000\ 000000000000000000000000000000000000000000008ac7230489e800000000\ 00000000000000000000000000000000000000000000c249fdd3277800000000\ @@ -407,21 +407,6 @@ fn init_sale() -> StdResult<()> { Uint128::zero(), "total_contribution.amount != 0" ); - - let response = query( - deps.as_ref(), - mock_env(), - QueryMsg::TotalAllocation { - sale_id: Binary::from(sale_id), - token_index, - }, - )?; - let total_allocation: TotalAllocationResponse = from_binary(&response)?; - assert_eq!( - total_allocation.amount, - Uint128::zero(), - "total_allocation.amount != 0" - ); } Ok(()) diff --git a/terra/packages/icco/src/common.rs b/terra/packages/icco/src/common.rs index 10a2868a..c2674343 100644 --- a/terra/packages/icco/src/common.rs +++ b/terra/packages/icco/src/common.rs @@ -19,6 +19,7 @@ pub struct SaleTimes { pub struct SaleCore { pub token_address: Vec, pub token_chain: u16, + pub token_decimals: u8, pub token_amount: Uint256, pub min_raise: Uint256, pub max_raise: Uint256, @@ -50,7 +51,7 @@ pub struct Contribution { #[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)] pub struct Allocation { - pub allocated: Uint256, // actually Uint128, but will be serialized as Uint256 + pub allocated: Uint256, pub excess_contributed: Uint256, } @@ -85,6 +86,24 @@ pub struct SaleAborted<'a> { pub id: &'a [u8], } +impl SaleCore { + pub fn adjust_token_amount(&self, amount: Uint256, decimals: u8) -> StdResult { + let adjusted: Uint256; + if self.token_decimals > decimals { + let x = self.token_decimals - decimals; + adjusted = amount / Uint256::from(10u128).pow(x as u32); + } else { + let x = decimals - self.token_decimals; + adjusted = amount * Uint256::from(10u128).pow(x as u32); + } + + match to_uint128(adjusted) { + Some(value) => return Ok(value), + None => return CommonError::AmountExceedsUint128Max.std_err(), + } + } +} + impl AcceptedToken { pub const N_BYTES: usize = 50; @@ -107,14 +126,6 @@ impl AcceptedToken { } } -pub fn to_const_bytes32(data: &[u8], index: usize) -> [u8; 32] { - data.get_bytes32(index).get_const_bytes(0) -} - -pub fn to_u256(data: &[u8], index: usize) -> Uint256 { - Uint256::new(to_const_bytes32(data, index)) -} - impl Contribution { pub const NUM_BYTES: usize = 33; // 1 + 32 } @@ -125,7 +136,7 @@ impl Allocation { impl<'a> SaleInit<'a> { pub const PAYLOAD_ID: u8 = 1; - const INDEX_ACCEPTED_TOKENS_START: usize = 227; + const INDEX_ACCEPTED_TOKENS_START: usize = 228; pub fn get_sale_id(data: &'a [u8]) -> StdResult<&[u8]> { match data[0] { @@ -138,11 +149,12 @@ impl<'a> SaleInit<'a> { pub fn deserialize(id: &'a [u8], data: &'a [u8]) -> StdResult { let token_address = data.get_bytes32(33).to_vec(); let token_chain = data.get_u16(65); - let token_amount = to_u256(data, 67); - let min_raise = to_u256(data, 99); - let max_raise = to_u256(data, 131); - let start = data.get_u64(163 + 24); // encoded as u256, but we only care about u64 time - let end = data.get_u64(195 + 24); // encoded as u256, but we only care about u64 for time + let token_decimals = data[67]; // TODO: double-check this is correct + let token_amount = to_u256(data, 68); + let min_raise = to_u256(data, 100); + let max_raise = to_u256(data, 132); + let start = data.get_u64(164 + 24); // encoded as u256, but we only care about u64 time + let end = data.get_u64(196 + 24); // encoded as u256, but we only care about u64 for time let accepted_tokens = SaleInit::deserialize_tokens(&data[SaleInit::INDEX_ACCEPTED_TOKENS_START..])?; @@ -159,6 +171,7 @@ impl<'a> SaleInit<'a> { core: SaleCore { token_address, token_chain, + token_decimals, token_amount, min_raise, max_raise, @@ -208,8 +221,7 @@ impl<'a> ContributionsSealed<'a> { return Err(StdError::generic_err("cannot exceed length 256")); } - let result = contributions.iter().find(|c| c.token_index == token_index); - if result != None { + if let Some(_) = contributions.iter().find(|c| c.token_index == token_index) { return Err(StdError::generic_err( "token_index already in contributions", )); @@ -278,31 +290,19 @@ impl<'a> SaleSealed<'a> { data: &[u8], expected_num_allocations: u8, indices: &Vec, - ) -> StdResult> { + ) -> StdResult> { if data[33] != expected_num_allocations { return Err(StdError::generic_err("encoded num_allocations != expected")); } - let mut parsed: Vec<(u8, AssetAllocation)> = Vec::with_capacity(indices.len()); + let mut parsed: Vec<(u8, Allocation)> = Vec::with_capacity(indices.len()); for &token_index in indices { let i = SaleSealed::HEADER_LEN + (token_index as usize) * Allocation::NUM_BYTES; - - // allocated - let (invalid, allocated) = data.get_u256(i); - if invalid > 0 { - return Err(StdError::generic_err("allocated too large")); - } - - // excess_contribution - let (invalid, excess_contributed) = data.get_u256(i + 32); - if invalid > 0 { - return Err(StdError::generic_err("excess_contributed too large")); - } parsed.push(( token_index, - AssetAllocation { - allocated: allocated.into(), - excess_contributed: excess_contributed.into(), + Allocation { + allocated: to_u256(data, i + 1), + excess_contributed: to_u256(data, i + 33), }, )); } @@ -337,6 +337,14 @@ impl<'a> SaleAborted<'a> { */ } +fn to_const_bytes32(data: &[u8], index: usize) -> [u8; 32] { + data.get_bytes32(index).get_const_bytes(0) +} + +fn to_u256(data: &[u8], index: usize) -> Uint256 { + Uint256::new(to_const_bytes32(data, index)) +} + pub fn make_asset_info(api: &dyn Api, addr: &[u8]) -> StdResult { match addr[0] { 1u8 => { @@ -361,3 +369,13 @@ pub fn make_asset_info(api: &dyn Api, addr: &[u8]) -> StdResult { } } } + +pub fn to_uint128(value: Uint256) -> Option { + if value > Uint256::from(u128::MAX) { + return None; + } + + let bytes = value.to_be_bytes(); + let (_, value) = bytes.as_slice().get_u256(0); + Some(value.into()) +} diff --git a/terra/packages/icco/src/error.rs b/terra/packages/icco/src/error.rs index e9177128..b3b65c39 100644 --- a/terra/packages/icco/src/error.rs +++ b/terra/packages/icco/src/error.rs @@ -3,6 +3,9 @@ use thiserror::Error; #[derive(Error, Debug)] pub enum CommonError { + #[error("AmountExceedsUint128Max")] + AmountExceedsUint128Max, + #[error("InvalidVaaAction")] InvalidVaaAction, } diff --git a/terra/scripts/helpers.ts b/terra/scripts/helpers.ts index 63d61235..5a18364c 100644 --- a/terra/scripts/helpers.ts +++ b/terra/scripts/helpers.ts @@ -15,8 +15,6 @@ import { Wallet, } from "@terra-money/terra.js"; import { readFileSync, writeFileSync, existsSync } from "fs"; -import path from "path"; -import { CustomError } from "ts-custom-error"; const DEFAULT_GAS_CURRENCY = "uusd"; const DEFAULT_GAS_PRICE = 0.15; @@ -49,10 +47,7 @@ export function newLocalClient(): Client { return newClient("localterra", undefined); } -export function newClient( - network: string, - mnemonic: string | undefined -): Client { +export function newClient(network: string, mnemonic: string | undefined): Client { if (network == "mainnet" || network == "testnet") { if (mnemonic === undefined) { throw Error("mnemonic undefined"); @@ -90,16 +85,6 @@ export async function sleep(timeout: number) { await new Promise((resolve) => setTimeout(resolve, timeout)); } -export class TransactionError extends CustomError { - public constructor( - public code: number, - public codespace: string | undefined, - public rawLog: string - ) { - super("transaction failed"); - } -} - export async function createTransaction(wallet: Wallet, msg: Msg) { let gas_currency = process.env.GAS_CURRENCY! || DEFAULT_GAS_CURRENCY; let gas_price = process.env.GAS_PRICE! || DEFAULT_GAS_PRICE; @@ -115,24 +100,12 @@ export async function broadcastTransaction(terra: LCDClient, signedTx: Tx) { return result; } -export async function performTransaction( - terra: LCDClient, - wallet: Wallet, - msg: Msg -) { +export async function performTransaction(terra: LCDClient, wallet: Wallet, msg: Msg) { const signedTx = await createTransaction(wallet, msg); - const result = await broadcastTransaction(terra, signedTx); - //if (isTxError(result)) { - // throw new TransactionError(parseInt(result.code), result.codespace, result.raw_log); - //} - return result; + return broadcastTransaction(terra, signedTx); } -export async function uploadContract( - terra: LCDClient, - wallet: Wallet, - filepath: string -) { +export async function uploadContract(terra: LCDClient, wallet: Wallet, filepath: string) { const contract = readFileSync(filepath, "base64"); const uploadMsg = new MsgStoreCode(wallet.key.accAddress, contract); const receipt = await performTransaction(terra, wallet, uploadMsg); @@ -164,19 +137,14 @@ export async function instantiateContract( } export async function executeContract( - terra: LCDClient, + //terra: LCDClient, wallet: Wallet, contractAddress: string, msg: object, coins?: Coins.Input ) { - const executeMsg = new MsgExecuteContract( - wallet.key.accAddress, - contractAddress, - msg, - coins - ); - return await performTransaction(terra, wallet, executeMsg); + const executeMsg = new MsgExecuteContract(wallet.key.accAddress, contractAddress, msg, coins); + return await performTransaction(wallet.lcd, wallet, executeMsg); } export async function queryContract( @@ -195,13 +163,7 @@ export async function deployContract( initMsg: object ) { const codeId = await uploadContract(terra, wallet, filepath); - return await instantiateContract( - terra, - wallet, - admin_address, - codeId, - initMsg - ); + return await instantiateContract(terra, wallet, admin_address, codeId, initMsg); } export async function migrate( @@ -211,12 +173,7 @@ export async function migrate( newCodeId: number, msg: object ) { - const migrateMsg = new MsgMigrateContract( - wallet.key.accAddress, - contractAddress, - newCodeId, - msg - ); + const migrateMsg = new MsgMigrateContract(wallet.key.accAddress, contractAddress, newCodeId, msg); return await performTransaction(terra, wallet, migrateMsg); } @@ -231,11 +188,7 @@ export async function update_contract_admin( contract_address: string, admin_address: string ) { - let msg = new MsgUpdateContractAdmin( - wallet.key.accAddress, - admin_address, - contract_address - ); + let msg = new MsgUpdateContractAdmin(wallet.key.accAddress, admin_address, contract_address); return await performTransaction(terra, wallet, msg); } diff --git a/terra/scripts/package-lock.json b/terra/scripts/package-lock.json index ad13d403..ad13a207 100644 --- a/terra/scripts/package-lock.json +++ b/terra/scripts/package-lock.json @@ -15,8 +15,11 @@ "bignumber.js": "^9.0.1", "dotenv": "^8.2.0", "elliptic": "^6.5.4", + "ethers": "^5.6.4", "prettier": "^2.6.1", "ts-custom-error": "^3.2.0", + "web3-eth-abi": "^1.7.3", + "web3-utils": "^1.7.3", "yargs": "^17.4.1" }, "devDependencies": { @@ -228,6 +231,162 @@ "node": "^10.12.0 || >=12.0.0" } }, + "node_modules/@ethersproject/abi": { + "version": "5.6.1", + "resolved": "https://registry.npmjs.org/@ethersproject/abi/-/abi-5.6.1.tgz", + "integrity": "sha512-0cqssYh6FXjlwKWBmLm3+zH2BNARoS5u/hxbz+LpQmcDB3w0W553h2btWui1/uZp2GBM/SI3KniTuMcYyHpA5w==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/address": "^5.6.0", + "@ethersproject/bignumber": "^5.6.0", + "@ethersproject/bytes": "^5.6.0", + "@ethersproject/constants": "^5.6.0", + "@ethersproject/hash": "^5.6.0", + "@ethersproject/keccak256": "^5.6.0", + "@ethersproject/logger": "^5.6.0", + "@ethersproject/properties": "^5.6.0", + "@ethersproject/strings": "^5.6.0" + } + }, + "node_modules/@ethersproject/abstract-provider": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/@ethersproject/abstract-provider/-/abstract-provider-5.6.0.tgz", + "integrity": "sha512-oPMFlKLN+g+y7a79cLK3WiLcjWFnZQtXWgnLAbHZcN3s7L4v90UHpTOrLk+m3yr0gt+/h9STTM6zrr7PM8uoRw==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/bignumber": "^5.6.0", + "@ethersproject/bytes": "^5.6.0", + "@ethersproject/logger": "^5.6.0", + "@ethersproject/networks": "^5.6.0", + "@ethersproject/properties": "^5.6.0", + "@ethersproject/transactions": "^5.6.0", + "@ethersproject/web": "^5.6.0" + } + }, + "node_modules/@ethersproject/abstract-signer": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/@ethersproject/abstract-signer/-/abstract-signer-5.6.0.tgz", + "integrity": "sha512-WOqnG0NJKtI8n0wWZPReHtaLkDByPL67tn4nBaDAhmVq8sjHTPbCdz4DRhVu/cfTOvfy9w3iq5QZ7BX7zw56BQ==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/abstract-provider": "^5.6.0", + "@ethersproject/bignumber": "^5.6.0", + "@ethersproject/bytes": "^5.6.0", + "@ethersproject/logger": "^5.6.0", + "@ethersproject/properties": "^5.6.0" + } + }, + "node_modules/@ethersproject/address": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/@ethersproject/address/-/address-5.6.0.tgz", + "integrity": "sha512-6nvhYXjbXsHPS+30sHZ+U4VMagFC/9zAk6Gd/h3S21YW4+yfb0WfRtaAIZ4kfM4rrVwqiy284LP0GtL5HXGLxQ==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/bignumber": "^5.6.0", + "@ethersproject/bytes": "^5.6.0", + "@ethersproject/keccak256": "^5.6.0", + "@ethersproject/logger": "^5.6.0", + "@ethersproject/rlp": "^5.6.0" + } + }, + "node_modules/@ethersproject/base64": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/@ethersproject/base64/-/base64-5.6.0.tgz", + "integrity": "sha512-2Neq8wxJ9xHxCF9TUgmKeSh9BXJ6OAxWfeGWvbauPh8FuHEjamgHilllx8KkSd5ErxyHIX7Xv3Fkcud2kY9ezw==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/bytes": "^5.6.0" + } + }, + "node_modules/@ethersproject/basex": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/@ethersproject/basex/-/basex-5.6.0.tgz", + "integrity": "sha512-qN4T+hQd/Md32MoJpc69rOwLYRUXwjTlhHDIeUkUmiN/JyWkkLLMoG0TqvSQKNqZOMgN5stbUYN6ILC+eD7MEQ==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/bytes": "^5.6.0", + "@ethersproject/properties": "^5.6.0" + } + }, + "node_modules/@ethersproject/bignumber": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/@ethersproject/bignumber/-/bignumber-5.6.0.tgz", + "integrity": "sha512-VziMaXIUHQlHJmkv1dlcd6GY2PmT0khtAqaMctCIDogxkrarMzA9L94KN1NeXqqOfFD6r0sJT3vCTOFSmZ07DA==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/bytes": "^5.6.0", + "@ethersproject/logger": "^5.6.0", + "bn.js": "^4.11.9" + } + }, + "node_modules/@ethersproject/bignumber/node_modules/bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + }, "node_modules/@ethersproject/bytes": { "version": "5.6.1", "resolved": "https://registry.npmjs.org/@ethersproject/bytes/-/bytes-5.6.1.tgz", @@ -246,6 +405,154 @@ "@ethersproject/logger": "^5.6.0" } }, + "node_modules/@ethersproject/constants": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/@ethersproject/constants/-/constants-5.6.0.tgz", + "integrity": "sha512-SrdaJx2bK0WQl23nSpV/b1aq293Lh0sUaZT/yYKPDKn4tlAbkH96SPJwIhwSwTsoQQZxuh1jnqsKwyymoiBdWA==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/bignumber": "^5.6.0" + } + }, + "node_modules/@ethersproject/contracts": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/@ethersproject/contracts/-/contracts-5.6.0.tgz", + "integrity": "sha512-74Ge7iqTDom0NX+mux8KbRUeJgu1eHZ3iv6utv++sLJG80FVuU9HnHeKVPfjd9s3woFhaFoQGf3B3iH/FrQmgw==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/abi": "^5.6.0", + "@ethersproject/abstract-provider": "^5.6.0", + "@ethersproject/abstract-signer": "^5.6.0", + "@ethersproject/address": "^5.6.0", + "@ethersproject/bignumber": "^5.6.0", + "@ethersproject/bytes": "^5.6.0", + "@ethersproject/constants": "^5.6.0", + "@ethersproject/logger": "^5.6.0", + "@ethersproject/properties": "^5.6.0", + "@ethersproject/transactions": "^5.6.0" + } + }, + "node_modules/@ethersproject/hash": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/@ethersproject/hash/-/hash-5.6.0.tgz", + "integrity": "sha512-fFd+k9gtczqlr0/BruWLAu7UAOas1uRRJvOR84uDf4lNZ+bTkGl366qvniUZHKtlqxBRU65MkOobkmvmpHU+jA==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/abstract-signer": "^5.6.0", + "@ethersproject/address": "^5.6.0", + "@ethersproject/bignumber": "^5.6.0", + "@ethersproject/bytes": "^5.6.0", + "@ethersproject/keccak256": "^5.6.0", + "@ethersproject/logger": "^5.6.0", + "@ethersproject/properties": "^5.6.0", + "@ethersproject/strings": "^5.6.0" + } + }, + "node_modules/@ethersproject/hdnode": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/@ethersproject/hdnode/-/hdnode-5.6.0.tgz", + "integrity": "sha512-61g3Jp3nwDqJcL/p4nugSyLrpl/+ChXIOtCEM8UDmWeB3JCAt5FoLdOMXQc3WWkc0oM2C0aAn6GFqqMcS/mHTw==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/abstract-signer": "^5.6.0", + "@ethersproject/basex": "^5.6.0", + "@ethersproject/bignumber": "^5.6.0", + "@ethersproject/bytes": "^5.6.0", + "@ethersproject/logger": "^5.6.0", + "@ethersproject/pbkdf2": "^5.6.0", + "@ethersproject/properties": "^5.6.0", + "@ethersproject/sha2": "^5.6.0", + "@ethersproject/signing-key": "^5.6.0", + "@ethersproject/strings": "^5.6.0", + "@ethersproject/transactions": "^5.6.0", + "@ethersproject/wordlists": "^5.6.0" + } + }, + "node_modules/@ethersproject/json-wallets": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/@ethersproject/json-wallets/-/json-wallets-5.6.0.tgz", + "integrity": "sha512-fmh86jViB9r0ibWXTQipxpAGMiuxoqUf78oqJDlCAJXgnJF024hOOX7qVgqsjtbeoxmcLwpPsXNU0WEe/16qPQ==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/abstract-signer": "^5.6.0", + "@ethersproject/address": "^5.6.0", + "@ethersproject/bytes": "^5.6.0", + "@ethersproject/hdnode": "^5.6.0", + "@ethersproject/keccak256": "^5.6.0", + "@ethersproject/logger": "^5.6.0", + "@ethersproject/pbkdf2": "^5.6.0", + "@ethersproject/properties": "^5.6.0", + "@ethersproject/random": "^5.6.0", + "@ethersproject/strings": "^5.6.0", + "@ethersproject/transactions": "^5.6.0", + "aes-js": "3.0.0", + "scrypt-js": "3.0.1" + } + }, + "node_modules/@ethersproject/keccak256": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/@ethersproject/keccak256/-/keccak256-5.6.0.tgz", + "integrity": "sha512-tk56BJ96mdj/ksi7HWZVWGjCq0WVl/QvfhFQNeL8fxhBlGoP+L80uDCiQcpJPd+2XxkivS3lwRm3E0CXTfol0w==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/bytes": "^5.6.0", + "js-sha3": "0.8.0" + } + }, "node_modules/@ethersproject/logger": { "version": "5.6.0", "resolved": "https://registry.npmjs.org/@ethersproject/logger/-/logger-5.6.0.tgz", @@ -261,6 +568,160 @@ } ] }, + "node_modules/@ethersproject/networks": { + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/@ethersproject/networks/-/networks-5.6.2.tgz", + "integrity": "sha512-9uEzaJY7j5wpYGTojGp8U89mSsgQLc40PCMJLMCnFXTs7nhBveZ0t7dbqWUNrepWTszDbFkYD6WlL8DKx5huHA==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/logger": "^5.6.0" + } + }, + "node_modules/@ethersproject/pbkdf2": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/@ethersproject/pbkdf2/-/pbkdf2-5.6.0.tgz", + "integrity": "sha512-Wu1AxTgJo3T3H6MIu/eejLFok9TYoSdgwRr5oGY1LTLfmGesDoSx05pemsbrPT2gG4cQME+baTSCp5sEo2erZQ==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/bytes": "^5.6.0", + "@ethersproject/sha2": "^5.6.0" + } + }, + "node_modules/@ethersproject/properties": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/@ethersproject/properties/-/properties-5.6.0.tgz", + "integrity": "sha512-szoOkHskajKePTJSZ46uHUWWkbv7TzP2ypdEK6jGMqJaEt2sb0jCgfBo0gH0m2HBpRixMuJ6TBRaQCF7a9DoCg==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/logger": "^5.6.0" + } + }, + "node_modules/@ethersproject/providers": { + "version": "5.6.4", + "resolved": "https://registry.npmjs.org/@ethersproject/providers/-/providers-5.6.4.tgz", + "integrity": "sha512-WAdknnaZ52hpHV3qPiJmKx401BLpup47h36Axxgre9zT+doa/4GC/Ne48ICPxTm0BqndpToHjpLP1ZnaxyE+vw==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/abstract-provider": "^5.6.0", + "@ethersproject/abstract-signer": "^5.6.0", + "@ethersproject/address": "^5.6.0", + "@ethersproject/basex": "^5.6.0", + "@ethersproject/bignumber": "^5.6.0", + "@ethersproject/bytes": "^5.6.0", + "@ethersproject/constants": "^5.6.0", + "@ethersproject/hash": "^5.6.0", + "@ethersproject/logger": "^5.6.0", + "@ethersproject/networks": "^5.6.0", + "@ethersproject/properties": "^5.6.0", + "@ethersproject/random": "^5.6.0", + "@ethersproject/rlp": "^5.6.0", + "@ethersproject/sha2": "^5.6.0", + "@ethersproject/strings": "^5.6.0", + "@ethersproject/transactions": "^5.6.0", + "@ethersproject/web": "^5.6.0", + "bech32": "1.1.4", + "ws": "7.4.6" + } + }, + "node_modules/@ethersproject/providers/node_modules/bech32": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/bech32/-/bech32-1.1.4.tgz", + "integrity": "sha512-s0IrSOzLlbvX7yp4WBfPITzpAU8sqQcpsmwXDiKwrG4r491vwCO/XpejasRNl0piBMe/DvP4Tz0mIS/X1DPJBQ==" + }, + "node_modules/@ethersproject/providers/node_modules/ws": { + "version": "7.4.6", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.6.tgz", + "integrity": "sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A==", + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/@ethersproject/random": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/@ethersproject/random/-/random-5.6.0.tgz", + "integrity": "sha512-si0PLcLjq+NG/XHSZz90asNf+YfKEqJGVdxoEkSukzbnBgC8rydbgbUgBbBGLeHN4kAJwUFEKsu3sCXT93YMsw==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/bytes": "^5.6.0", + "@ethersproject/logger": "^5.6.0" + } + }, + "node_modules/@ethersproject/rlp": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/@ethersproject/rlp/-/rlp-5.6.0.tgz", + "integrity": "sha512-dz9WR1xpcTL+9DtOT/aDO+YyxSSdO8YIS0jyZwHHSlAmnxA6cKU3TrTd4Xc/bHayctxTgGLYNuVVoiXE4tTq1g==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/bytes": "^5.6.0", + "@ethersproject/logger": "^5.6.0" + } + }, "node_modules/@ethersproject/sha2": { "version": "5.6.0", "resolved": "https://registry.npmjs.org/@ethersproject/sha2/-/sha2-5.6.0.tgz", @@ -281,6 +742,199 @@ "hash.js": "1.1.7" } }, + "node_modules/@ethersproject/signing-key": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/@ethersproject/signing-key/-/signing-key-5.6.0.tgz", + "integrity": "sha512-S+njkhowmLeUu/r7ir8n78OUKx63kBdMCPssePS89So1TH4hZqnWFsThEd/GiXYp9qMxVrydf7KdM9MTGPFukA==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/bytes": "^5.6.0", + "@ethersproject/logger": "^5.6.0", + "@ethersproject/properties": "^5.6.0", + "bn.js": "^4.11.9", + "elliptic": "6.5.4", + "hash.js": "1.1.7" + } + }, + "node_modules/@ethersproject/signing-key/node_modules/bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + }, + "node_modules/@ethersproject/solidity": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/@ethersproject/solidity/-/solidity-5.6.0.tgz", + "integrity": "sha512-YwF52vTNd50kjDzqKaoNNbC/r9kMDPq3YzDWmsjFTRBcIF1y4JCQJ8gB30wsTfHbaxgxelI5BfxQSxD/PbJOww==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/bignumber": "^5.6.0", + "@ethersproject/bytes": "^5.6.0", + "@ethersproject/keccak256": "^5.6.0", + "@ethersproject/logger": "^5.6.0", + "@ethersproject/sha2": "^5.6.0", + "@ethersproject/strings": "^5.6.0" + } + }, + "node_modules/@ethersproject/strings": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/@ethersproject/strings/-/strings-5.6.0.tgz", + "integrity": "sha512-uv10vTtLTZqrJuqBZR862ZQjTIa724wGPWQqZrofaPI/kUsf53TBG0I0D+hQ1qyNtllbNzaW+PDPHHUI6/65Mg==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/bytes": "^5.6.0", + "@ethersproject/constants": "^5.6.0", + "@ethersproject/logger": "^5.6.0" + } + }, + "node_modules/@ethersproject/transactions": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/@ethersproject/transactions/-/transactions-5.6.0.tgz", + "integrity": "sha512-4HX+VOhNjXHZyGzER6E/LVI2i6lf9ejYeWD6l4g50AdmimyuStKc39kvKf1bXWQMg7QNVh+uC7dYwtaZ02IXeg==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/address": "^5.6.0", + "@ethersproject/bignumber": "^5.6.0", + "@ethersproject/bytes": "^5.6.0", + "@ethersproject/constants": "^5.6.0", + "@ethersproject/keccak256": "^5.6.0", + "@ethersproject/logger": "^5.6.0", + "@ethersproject/properties": "^5.6.0", + "@ethersproject/rlp": "^5.6.0", + "@ethersproject/signing-key": "^5.6.0" + } + }, + "node_modules/@ethersproject/units": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/@ethersproject/units/-/units-5.6.0.tgz", + "integrity": "sha512-tig9x0Qmh8qbo1w8/6tmtyrm/QQRviBh389EQ+d8fP4wDsBrJBf08oZfoiz1/uenKK9M78yAP4PoR7SsVoTjsw==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/bignumber": "^5.6.0", + "@ethersproject/constants": "^5.6.0", + "@ethersproject/logger": "^5.6.0" + } + }, + "node_modules/@ethersproject/wallet": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/@ethersproject/wallet/-/wallet-5.6.0.tgz", + "integrity": "sha512-qMlSdOSTyp0MBeE+r7SUhr1jjDlC1zAXB8VD84hCnpijPQiSNbxr6GdiLXxpUs8UKzkDiNYYC5DRI3MZr+n+tg==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/abstract-provider": "^5.6.0", + "@ethersproject/abstract-signer": "^5.6.0", + "@ethersproject/address": "^5.6.0", + "@ethersproject/bignumber": "^5.6.0", + "@ethersproject/bytes": "^5.6.0", + "@ethersproject/hash": "^5.6.0", + "@ethersproject/hdnode": "^5.6.0", + "@ethersproject/json-wallets": "^5.6.0", + "@ethersproject/keccak256": "^5.6.0", + "@ethersproject/logger": "^5.6.0", + "@ethersproject/properties": "^5.6.0", + "@ethersproject/random": "^5.6.0", + "@ethersproject/signing-key": "^5.6.0", + "@ethersproject/transactions": "^5.6.0", + "@ethersproject/wordlists": "^5.6.0" + } + }, + "node_modules/@ethersproject/web": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/@ethersproject/web/-/web-5.6.0.tgz", + "integrity": "sha512-G/XHj0hV1FxI2teHRfCGvfBUHFmU+YOSbCxlAMqJklxSa7QMiHFQfAxvwY2PFqgvdkxEKwRNr/eCjfAPEm2Ctg==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/base64": "^5.6.0", + "@ethersproject/bytes": "^5.6.0", + "@ethersproject/logger": "^5.6.0", + "@ethersproject/properties": "^5.6.0", + "@ethersproject/strings": "^5.6.0" + } + }, + "node_modules/@ethersproject/wordlists": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/@ethersproject/wordlists/-/wordlists-5.6.0.tgz", + "integrity": "sha512-q0bxNBfIX3fUuAo9OmjlEYxP40IB8ABgb7HjEZCL5IKubzV3j30CWi2rqQbjTS2HfoyQbfINoKcTVWP4ejwR7Q==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/bytes": "^5.6.0", + "@ethersproject/hash": "^5.6.0", + "@ethersproject/logger": "^5.6.0", + "@ethersproject/properties": "^5.6.0", + "@ethersproject/strings": "^5.6.0" + } + }, "node_modules/@humanwhocodes/config-array": { "version": "0.5.0", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.5.0.tgz", @@ -513,6 +1167,14 @@ "integrity": "sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA==", "dev": true }, + "node_modules/@types/bn.js": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@types/bn.js/-/bn.js-5.1.0.tgz", + "integrity": "sha512-QSSVYj7pYFN49kW77o2s9xTCwZ8F2xLbjLLSEVh8D2F4JUhZtPAGOFLTD+ffqksBx/u4cE/KImFjyhqCjn/LIA==", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/connect": { "version": "3.4.35", "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz", @@ -546,6 +1208,14 @@ "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.29.tgz", "integrity": "sha512-tx5jMmMFwx7wBwq/V7OohKDVb/JwJU5qCVkeLMh1//xycAJ/ESuw9aJ9SEtlCZDYi2pBfe4JkisSoAtbOsBNAA==" }, + "node_modules/@types/pbkdf2": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@types/pbkdf2/-/pbkdf2-3.1.0.tgz", + "integrity": "sha512-Cf63Rv7jCQ0LaL8tNXmEyqTHuIJxRdlS5vMh1mj5voN4+QFhVZnlZruezqpWYDiJ8UTzhP0VmeLXCmBk66YrMQ==", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/qs": { "version": "6.9.7", "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz", @@ -556,6 +1226,14 @@ "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.4.tgz", "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==" }, + "node_modules/@types/secp256k1": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@types/secp256k1/-/secp256k1-4.0.3.tgz", + "integrity": "sha512-Da66lEIFeIz9ltsdMZcpQvmrmmoqrfju8pm1BH8WbYjZSwUgCwXLb9C+9XYogwBITnbsSaMdVPb2ekf7TV+03w==", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/ws": { "version": "7.4.7", "resolved": "https://registry.npmjs.org/@types/ws/-/ws-7.4.7.tgz", @@ -609,6 +1287,11 @@ "node": ">=0.4.0" } }, + "node_modules/aes-js": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/aes-js/-/aes-js-3.0.0.tgz", + "integrity": "sha1-4h3xCtbCBTKVvLuNq0Cwnb6ofk0=" + }, "node_modules/ajv": { "version": "6.12.6", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", @@ -779,6 +1462,11 @@ "resolved": "https://registry.npmjs.org/@types/node/-/node-11.11.6.tgz", "integrity": "sha512-Exw4yUWMBXM3X+8oqzJNRqZSwUAaS4+7NdvHqQuFi/d+synz++xmX3QIf+BFqneW8N31R8Ky+sikfZUXq07ggQ==" }, + "node_modules/blakejs": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/blakejs/-/blakejs-1.2.1.tgz", + "integrity": "sha512-QXUSXI3QVc/gJME0dBpXrag1kbzOqCjCX8/b54ntNyW6sjtoqxqRk3LTmXzaJoh71zMsDCjM+47jS7XiwN/+fQ==" + }, "node_modules/bn.js": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.0.tgz", @@ -813,6 +1501,19 @@ "resolved": "https://registry.npmjs.org/browser-headers/-/browser-headers-0.4.1.tgz", "integrity": "sha512-CA9hsySZVo9371qEHjHZtYxV2cFtVj5Wj/ZHi8ooEsrtm4vOnl9Y9HmyYWk9q+05d7K3rdoAE0j3MVEFVvtQtg==" }, + "node_modules/browserify-aes": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", + "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", + "dependencies": { + "buffer-xor": "^1.0.3", + "cipher-base": "^1.0.0", + "create-hash": "^1.1.0", + "evp_bytestokey": "^1.0.3", + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, "node_modules/bs58": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/bs58/-/bs58-4.0.1.tgz", @@ -862,6 +1563,11 @@ "node": ">=4.5" } }, + "node_modules/buffer-xor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", + "integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=" + }, "node_modules/bufferutil": { "version": "4.0.6", "resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-4.0.6.tgz", @@ -1333,11 +2039,130 @@ "node": ">=0.10.0" } }, + "node_modules/ethereum-bloom-filters": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/ethereum-bloom-filters/-/ethereum-bloom-filters-1.0.10.tgz", + "integrity": "sha512-rxJ5OFN3RwjQxDcFP2Z5+Q9ho4eIdEmSc2ht0fCu8Se9nbXjZ7/031uXoUYJ87KHCOdVeiUuwSnoS7hmYAGVHA==", + "dependencies": { + "js-sha3": "^0.8.0" + } + }, + "node_modules/ethereum-cryptography": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", + "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==", + "dependencies": { + "@types/pbkdf2": "^3.0.0", + "@types/secp256k1": "^4.0.1", + "blakejs": "^1.1.0", + "browserify-aes": "^1.2.0", + "bs58check": "^2.1.2", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "hash.js": "^1.1.7", + "keccak": "^3.0.0", + "pbkdf2": "^3.0.17", + "randombytes": "^2.1.0", + "safe-buffer": "^5.1.2", + "scrypt-js": "^3.0.0", + "secp256k1": "^4.0.1", + "setimmediate": "^1.0.5" + } + }, + "node_modules/ethereumjs-util": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-7.1.4.tgz", + "integrity": "sha512-p6KmuPCX4mZIqsQzXfmSx9Y0l2hqf+VkAiwSisW3UKUFdk8ZkAt+AYaor83z2nSi6CU2zSsXMlD80hAbNEGM0A==", + "dependencies": { + "@types/bn.js": "^5.1.0", + "bn.js": "^5.1.2", + "create-hash": "^1.1.2", + "ethereum-cryptography": "^0.1.3", + "rlp": "^2.2.4" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/ethers": { + "version": "5.6.4", + "resolved": "https://registry.npmjs.org/ethers/-/ethers-5.6.4.tgz", + "integrity": "sha512-62UIfxAQXdf67TeeOaoOoPctm5hUlYgfd0iW3wxfj7qRYKDcvvy0f+sJ3W2/Pyx77R8dblvejA8jokj+lS+ATQ==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/abi": "5.6.1", + "@ethersproject/abstract-provider": "5.6.0", + "@ethersproject/abstract-signer": "5.6.0", + "@ethersproject/address": "5.6.0", + "@ethersproject/base64": "5.6.0", + "@ethersproject/basex": "5.6.0", + "@ethersproject/bignumber": "5.6.0", + "@ethersproject/bytes": "5.6.1", + "@ethersproject/constants": "5.6.0", + "@ethersproject/contracts": "5.6.0", + "@ethersproject/hash": "5.6.0", + "@ethersproject/hdnode": "5.6.0", + "@ethersproject/json-wallets": "5.6.0", + "@ethersproject/keccak256": "5.6.0", + "@ethersproject/logger": "5.6.0", + "@ethersproject/networks": "5.6.2", + "@ethersproject/pbkdf2": "5.6.0", + "@ethersproject/properties": "5.6.0", + "@ethersproject/providers": "5.6.4", + "@ethersproject/random": "5.6.0", + "@ethersproject/rlp": "5.6.0", + "@ethersproject/sha2": "5.6.0", + "@ethersproject/signing-key": "5.6.0", + "@ethersproject/solidity": "5.6.0", + "@ethersproject/strings": "5.6.0", + "@ethersproject/transactions": "5.6.0", + "@ethersproject/units": "5.6.0", + "@ethersproject/wallet": "5.6.0", + "@ethersproject/web": "5.6.0", + "@ethersproject/wordlists": "5.6.0" + } + }, + "node_modules/ethjs-unit": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/ethjs-unit/-/ethjs-unit-0.1.6.tgz", + "integrity": "sha1-xmWSHkduh7ziqdWIpv4EBbLEFpk=", + "dependencies": { + "bn.js": "4.11.6", + "number-to-bn": "1.7.0" + }, + "engines": { + "node": ">=6.5.0", + "npm": ">=3" + } + }, + "node_modules/ethjs-unit/node_modules/bn.js": { + "version": "4.11.6", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.6.tgz", + "integrity": "sha1-UzRK2xRhehP26N0s4okF0cC6MhU=" + }, "node_modules/eventemitter3": { "version": "4.0.7", "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==" }, + "node_modules/evp_bytestokey": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", + "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", + "dependencies": { + "md5.js": "^1.3.4", + "safe-buffer": "^5.1.1" + } + }, "node_modules/eyes": { "version": "0.1.8", "resolved": "https://registry.npmjs.org/eyes/-/eyes-0.1.8.tgz", @@ -1626,6 +2451,15 @@ "node": ">=0.10.0" } }, + "node_modules/is-hex-prefixed": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-hex-prefixed/-/is-hex-prefixed-1.0.0.tgz", + "integrity": "sha1-fY035q135dEnFIkTxXPggtd39VQ=", + "engines": { + "node": ">=6.5.0", + "npm": ">=3" + } + }, "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", @@ -1750,6 +2584,20 @@ "node": "*" } }, + "node_modules/keccak": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/keccak/-/keccak-3.0.2.tgz", + "integrity": "sha512-PyKKjkH53wDMLGrvmRGSNWgmSxZOUqbnXwKL9tmgbFYA1iAYqW21kfR7mZXV0MlESiefxQQE9X9fTa3X+2MPDQ==", + "hasInstallScript": true, + "dependencies": { + "node-addon-api": "^2.0.0", + "node-gyp-build": "^4.2.0", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, "node_modules/levn": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", @@ -1885,6 +2733,24 @@ "node-gyp-build-test": "build-test.js" } }, + "node_modules/number-to-bn": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/number-to-bn/-/number-to-bn-1.7.0.tgz", + "integrity": "sha1-uzYjWS9+X54AMLGXe9QaDFP+HqA=", + "dependencies": { + "bn.js": "4.11.6", + "strip-hex-prefix": "1.0.0" + }, + "engines": { + "node": ">=6.5.0", + "npm": ">=3" + } + }, + "node_modules/number-to-bn/node_modules/bn.js": { + "version": "4.11.6", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.6.tgz", + "integrity": "sha1-UzRK2xRhehP26N0s4okF0cC6MhU=" + }, "node_modules/once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -2107,6 +2973,17 @@ "inherits": "^2.0.1" } }, + "node_modules/rlp": { + "version": "2.2.7", + "resolved": "https://registry.npmjs.org/rlp/-/rlp-2.2.7.tgz", + "integrity": "sha512-d5gdPmgQ0Z+AklL2NVXr/IoSjNZFfTVvQWzL/AM2AOcSzYP2xjlb0AC8YyCLc41MSNf6P6QVtjgPdmVtzb+4lQ==", + "dependencies": { + "bn.js": "^5.2.0" + }, + "bin": { + "rlp": "bin/rlp" + } + }, "node_modules/rpc-websockets": { "version": "7.4.18", "resolved": "https://registry.npmjs.org/rpc-websockets/-/rpc-websockets-7.4.18.tgz", @@ -2173,6 +3050,11 @@ } ] }, + "node_modules/scrypt-js": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/scrypt-js/-/scrypt-js-3.0.1.tgz", + "integrity": "sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA==" + }, "node_modules/secp256k1": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/secp256k1/-/secp256k1-4.0.3.tgz", @@ -2202,6 +3084,11 @@ "node": ">=10" } }, + "node_modules/setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=" + }, "node_modules/sha.js": { "version": "2.4.11", "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", @@ -2290,6 +3177,18 @@ "node": ">=8" } }, + "node_modules/strip-hex-prefix": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-hex-prefix/-/strip-hex-prefix-1.0.0.tgz", + "integrity": "sha1-DF8VX+8RUTczd96du1iNoFUA428=", + "dependencies": { + "is-hex-prefixed": "1.0.0" + }, + "engines": { + "node": ">=6.5.0", + "npm": ">=3" + } + }, "node_modules/strip-json-comments": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", @@ -2546,6 +3445,11 @@ "node": ">=6.14.2" } }, + "node_modules/utf8": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/utf8/-/utf8-3.0.0.tgz", + "integrity": "sha512-E8VjFIQ/TyQgp+TZfS6l8yp/xWppSAHzidGiRrqe4bK4XP9pTRyKFgGJpO3SN7zdX4DeomTrwaseCHovfpFcqQ==" + }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -2571,6 +3475,56 @@ "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", "dev": true }, + "node_modules/web3-eth-abi": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/web3-eth-abi/-/web3-eth-abi-1.7.3.tgz", + "integrity": "sha512-ZlD8DrJro0ocnbZViZpAoMX44x5aYAb73u2tMq557rMmpiluZNnhcCYF/NnVMy6UIkn7SF/qEA45GXA1ne6Tnw==", + "dependencies": { + "@ethersproject/abi": "5.0.7", + "web3-utils": "1.7.3" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-eth-abi/node_modules/@ethersproject/abi": { + "version": "5.0.7", + "resolved": "https://registry.npmjs.org/@ethersproject/abi/-/abi-5.0.7.tgz", + "integrity": "sha512-Cqktk+hSIckwP/W8O47Eef60VwmoSC/L3lY0+dIBhQPCNn9E4V7rwmm2aFrNRRDJfFlGuZ1khkQUOc3oBX+niw==", + "dependencies": { + "@ethersproject/address": "^5.0.4", + "@ethersproject/bignumber": "^5.0.7", + "@ethersproject/bytes": "^5.0.4", + "@ethersproject/constants": "^5.0.4", + "@ethersproject/hash": "^5.0.4", + "@ethersproject/keccak256": "^5.0.3", + "@ethersproject/logger": "^5.0.5", + "@ethersproject/properties": "^5.0.3", + "@ethersproject/strings": "^5.0.4" + } + }, + "node_modules/web3-utils": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/web3-utils/-/web3-utils-1.7.3.tgz", + "integrity": "sha512-g6nQgvb/bUpVUIxJE+ezVN+rYwYmlFyMvMIRSuqpi1dk6ApDD00YNArrk7sPcZnjvxOJ76813Xs2vIN2rgh4lg==", + "dependencies": { + "bn.js": "^4.11.9", + "ethereum-bloom-filters": "^1.0.6", + "ethereumjs-util": "^7.1.0", + "ethjs-unit": "0.1.6", + "number-to-bn": "1.7.0", + "randombytes": "^2.1.0", + "utf8": "3.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/web3-utils/node_modules/bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + }, "node_modules/webidl-conversions": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", @@ -2880,6 +3834,94 @@ "strip-json-comments": "^3.1.1" } }, + "@ethersproject/abi": { + "version": "5.6.1", + "resolved": "https://registry.npmjs.org/@ethersproject/abi/-/abi-5.6.1.tgz", + "integrity": "sha512-0cqssYh6FXjlwKWBmLm3+zH2BNARoS5u/hxbz+LpQmcDB3w0W553h2btWui1/uZp2GBM/SI3KniTuMcYyHpA5w==", + "requires": { + "@ethersproject/address": "^5.6.0", + "@ethersproject/bignumber": "^5.6.0", + "@ethersproject/bytes": "^5.6.0", + "@ethersproject/constants": "^5.6.0", + "@ethersproject/hash": "^5.6.0", + "@ethersproject/keccak256": "^5.6.0", + "@ethersproject/logger": "^5.6.0", + "@ethersproject/properties": "^5.6.0", + "@ethersproject/strings": "^5.6.0" + } + }, + "@ethersproject/abstract-provider": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/@ethersproject/abstract-provider/-/abstract-provider-5.6.0.tgz", + "integrity": "sha512-oPMFlKLN+g+y7a79cLK3WiLcjWFnZQtXWgnLAbHZcN3s7L4v90UHpTOrLk+m3yr0gt+/h9STTM6zrr7PM8uoRw==", + "requires": { + "@ethersproject/bignumber": "^5.6.0", + "@ethersproject/bytes": "^5.6.0", + "@ethersproject/logger": "^5.6.0", + "@ethersproject/networks": "^5.6.0", + "@ethersproject/properties": "^5.6.0", + "@ethersproject/transactions": "^5.6.0", + "@ethersproject/web": "^5.6.0" + } + }, + "@ethersproject/abstract-signer": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/@ethersproject/abstract-signer/-/abstract-signer-5.6.0.tgz", + "integrity": "sha512-WOqnG0NJKtI8n0wWZPReHtaLkDByPL67tn4nBaDAhmVq8sjHTPbCdz4DRhVu/cfTOvfy9w3iq5QZ7BX7zw56BQ==", + "requires": { + "@ethersproject/abstract-provider": "^5.6.0", + "@ethersproject/bignumber": "^5.6.0", + "@ethersproject/bytes": "^5.6.0", + "@ethersproject/logger": "^5.6.0", + "@ethersproject/properties": "^5.6.0" + } + }, + "@ethersproject/address": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/@ethersproject/address/-/address-5.6.0.tgz", + "integrity": "sha512-6nvhYXjbXsHPS+30sHZ+U4VMagFC/9zAk6Gd/h3S21YW4+yfb0WfRtaAIZ4kfM4rrVwqiy284LP0GtL5HXGLxQ==", + "requires": { + "@ethersproject/bignumber": "^5.6.0", + "@ethersproject/bytes": "^5.6.0", + "@ethersproject/keccak256": "^5.6.0", + "@ethersproject/logger": "^5.6.0", + "@ethersproject/rlp": "^5.6.0" + } + }, + "@ethersproject/base64": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/@ethersproject/base64/-/base64-5.6.0.tgz", + "integrity": "sha512-2Neq8wxJ9xHxCF9TUgmKeSh9BXJ6OAxWfeGWvbauPh8FuHEjamgHilllx8KkSd5ErxyHIX7Xv3Fkcud2kY9ezw==", + "requires": { + "@ethersproject/bytes": "^5.6.0" + } + }, + "@ethersproject/basex": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/@ethersproject/basex/-/basex-5.6.0.tgz", + "integrity": "sha512-qN4T+hQd/Md32MoJpc69rOwLYRUXwjTlhHDIeUkUmiN/JyWkkLLMoG0TqvSQKNqZOMgN5stbUYN6ILC+eD7MEQ==", + "requires": { + "@ethersproject/bytes": "^5.6.0", + "@ethersproject/properties": "^5.6.0" + } + }, + "@ethersproject/bignumber": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/@ethersproject/bignumber/-/bignumber-5.6.0.tgz", + "integrity": "sha512-VziMaXIUHQlHJmkv1dlcd6GY2PmT0khtAqaMctCIDogxkrarMzA9L94KN1NeXqqOfFD6r0sJT3vCTOFSmZ07DA==", + "requires": { + "@ethersproject/bytes": "^5.6.0", + "@ethersproject/logger": "^5.6.0", + "bn.js": "^4.11.9" + }, + "dependencies": { + "bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + } + } + }, "@ethersproject/bytes": { "version": "5.6.1", "resolved": "https://registry.npmjs.org/@ethersproject/bytes/-/bytes-5.6.1.tgz", @@ -2888,11 +3930,181 @@ "@ethersproject/logger": "^5.6.0" } }, + "@ethersproject/constants": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/@ethersproject/constants/-/constants-5.6.0.tgz", + "integrity": "sha512-SrdaJx2bK0WQl23nSpV/b1aq293Lh0sUaZT/yYKPDKn4tlAbkH96SPJwIhwSwTsoQQZxuh1jnqsKwyymoiBdWA==", + "requires": { + "@ethersproject/bignumber": "^5.6.0" + } + }, + "@ethersproject/contracts": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/@ethersproject/contracts/-/contracts-5.6.0.tgz", + "integrity": "sha512-74Ge7iqTDom0NX+mux8KbRUeJgu1eHZ3iv6utv++sLJG80FVuU9HnHeKVPfjd9s3woFhaFoQGf3B3iH/FrQmgw==", + "requires": { + "@ethersproject/abi": "^5.6.0", + "@ethersproject/abstract-provider": "^5.6.0", + "@ethersproject/abstract-signer": "^5.6.0", + "@ethersproject/address": "^5.6.0", + "@ethersproject/bignumber": "^5.6.0", + "@ethersproject/bytes": "^5.6.0", + "@ethersproject/constants": "^5.6.0", + "@ethersproject/logger": "^5.6.0", + "@ethersproject/properties": "^5.6.0", + "@ethersproject/transactions": "^5.6.0" + } + }, + "@ethersproject/hash": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/@ethersproject/hash/-/hash-5.6.0.tgz", + "integrity": "sha512-fFd+k9gtczqlr0/BruWLAu7UAOas1uRRJvOR84uDf4lNZ+bTkGl366qvniUZHKtlqxBRU65MkOobkmvmpHU+jA==", + "requires": { + "@ethersproject/abstract-signer": "^5.6.0", + "@ethersproject/address": "^5.6.0", + "@ethersproject/bignumber": "^5.6.0", + "@ethersproject/bytes": "^5.6.0", + "@ethersproject/keccak256": "^5.6.0", + "@ethersproject/logger": "^5.6.0", + "@ethersproject/properties": "^5.6.0", + "@ethersproject/strings": "^5.6.0" + } + }, + "@ethersproject/hdnode": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/@ethersproject/hdnode/-/hdnode-5.6.0.tgz", + "integrity": "sha512-61g3Jp3nwDqJcL/p4nugSyLrpl/+ChXIOtCEM8UDmWeB3JCAt5FoLdOMXQc3WWkc0oM2C0aAn6GFqqMcS/mHTw==", + "requires": { + "@ethersproject/abstract-signer": "^5.6.0", + "@ethersproject/basex": "^5.6.0", + "@ethersproject/bignumber": "^5.6.0", + "@ethersproject/bytes": "^5.6.0", + "@ethersproject/logger": "^5.6.0", + "@ethersproject/pbkdf2": "^5.6.0", + "@ethersproject/properties": "^5.6.0", + "@ethersproject/sha2": "^5.6.0", + "@ethersproject/signing-key": "^5.6.0", + "@ethersproject/strings": "^5.6.0", + "@ethersproject/transactions": "^5.6.0", + "@ethersproject/wordlists": "^5.6.0" + } + }, + "@ethersproject/json-wallets": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/@ethersproject/json-wallets/-/json-wallets-5.6.0.tgz", + "integrity": "sha512-fmh86jViB9r0ibWXTQipxpAGMiuxoqUf78oqJDlCAJXgnJF024hOOX7qVgqsjtbeoxmcLwpPsXNU0WEe/16qPQ==", + "requires": { + "@ethersproject/abstract-signer": "^5.6.0", + "@ethersproject/address": "^5.6.0", + "@ethersproject/bytes": "^5.6.0", + "@ethersproject/hdnode": "^5.6.0", + "@ethersproject/keccak256": "^5.6.0", + "@ethersproject/logger": "^5.6.0", + "@ethersproject/pbkdf2": "^5.6.0", + "@ethersproject/properties": "^5.6.0", + "@ethersproject/random": "^5.6.0", + "@ethersproject/strings": "^5.6.0", + "@ethersproject/transactions": "^5.6.0", + "aes-js": "3.0.0", + "scrypt-js": "3.0.1" + } + }, + "@ethersproject/keccak256": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/@ethersproject/keccak256/-/keccak256-5.6.0.tgz", + "integrity": "sha512-tk56BJ96mdj/ksi7HWZVWGjCq0WVl/QvfhFQNeL8fxhBlGoP+L80uDCiQcpJPd+2XxkivS3lwRm3E0CXTfol0w==", + "requires": { + "@ethersproject/bytes": "^5.6.0", + "js-sha3": "0.8.0" + } + }, "@ethersproject/logger": { "version": "5.6.0", "resolved": "https://registry.npmjs.org/@ethersproject/logger/-/logger-5.6.0.tgz", "integrity": "sha512-BiBWllUROH9w+P21RzoxJKzqoqpkyM1pRnEKG69bulE9TSQD8SAIvTQqIMZmmCO8pUNkgLP1wndX1gKghSpBmg==" }, + "@ethersproject/networks": { + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/@ethersproject/networks/-/networks-5.6.2.tgz", + "integrity": "sha512-9uEzaJY7j5wpYGTojGp8U89mSsgQLc40PCMJLMCnFXTs7nhBveZ0t7dbqWUNrepWTszDbFkYD6WlL8DKx5huHA==", + "requires": { + "@ethersproject/logger": "^5.6.0" + } + }, + "@ethersproject/pbkdf2": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/@ethersproject/pbkdf2/-/pbkdf2-5.6.0.tgz", + "integrity": "sha512-Wu1AxTgJo3T3H6MIu/eejLFok9TYoSdgwRr5oGY1LTLfmGesDoSx05pemsbrPT2gG4cQME+baTSCp5sEo2erZQ==", + "requires": { + "@ethersproject/bytes": "^5.6.0", + "@ethersproject/sha2": "^5.6.0" + } + }, + "@ethersproject/properties": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/@ethersproject/properties/-/properties-5.6.0.tgz", + "integrity": "sha512-szoOkHskajKePTJSZ46uHUWWkbv7TzP2ypdEK6jGMqJaEt2sb0jCgfBo0gH0m2HBpRixMuJ6TBRaQCF7a9DoCg==", + "requires": { + "@ethersproject/logger": "^5.6.0" + } + }, + "@ethersproject/providers": { + "version": "5.6.4", + "resolved": "https://registry.npmjs.org/@ethersproject/providers/-/providers-5.6.4.tgz", + "integrity": "sha512-WAdknnaZ52hpHV3qPiJmKx401BLpup47h36Axxgre9zT+doa/4GC/Ne48ICPxTm0BqndpToHjpLP1ZnaxyE+vw==", + "requires": { + "@ethersproject/abstract-provider": "^5.6.0", + "@ethersproject/abstract-signer": "^5.6.0", + "@ethersproject/address": "^5.6.0", + "@ethersproject/basex": "^5.6.0", + "@ethersproject/bignumber": "^5.6.0", + "@ethersproject/bytes": "^5.6.0", + "@ethersproject/constants": "^5.6.0", + "@ethersproject/hash": "^5.6.0", + "@ethersproject/logger": "^5.6.0", + "@ethersproject/networks": "^5.6.0", + "@ethersproject/properties": "^5.6.0", + "@ethersproject/random": "^5.6.0", + "@ethersproject/rlp": "^5.6.0", + "@ethersproject/sha2": "^5.6.0", + "@ethersproject/strings": "^5.6.0", + "@ethersproject/transactions": "^5.6.0", + "@ethersproject/web": "^5.6.0", + "bech32": "1.1.4", + "ws": "7.4.6" + }, + "dependencies": { + "bech32": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/bech32/-/bech32-1.1.4.tgz", + "integrity": "sha512-s0IrSOzLlbvX7yp4WBfPITzpAU8sqQcpsmwXDiKwrG4r491vwCO/XpejasRNl0piBMe/DvP4Tz0mIS/X1DPJBQ==" + }, + "ws": { + "version": "7.4.6", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.6.tgz", + "integrity": "sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A==", + "requires": {} + } + } + }, + "@ethersproject/random": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/@ethersproject/random/-/random-5.6.0.tgz", + "integrity": "sha512-si0PLcLjq+NG/XHSZz90asNf+YfKEqJGVdxoEkSukzbnBgC8rydbgbUgBbBGLeHN4kAJwUFEKsu3sCXT93YMsw==", + "requires": { + "@ethersproject/bytes": "^5.6.0", + "@ethersproject/logger": "^5.6.0" + } + }, + "@ethersproject/rlp": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/@ethersproject/rlp/-/rlp-5.6.0.tgz", + "integrity": "sha512-dz9WR1xpcTL+9DtOT/aDO+YyxSSdO8YIS0jyZwHHSlAmnxA6cKU3TrTd4Xc/bHayctxTgGLYNuVVoiXE4tTq1g==", + "requires": { + "@ethersproject/bytes": "^5.6.0", + "@ethersproject/logger": "^5.6.0" + } + }, "@ethersproject/sha2": { "version": "5.6.0", "resolved": "https://registry.npmjs.org/@ethersproject/sha2/-/sha2-5.6.0.tgz", @@ -2903,6 +4115,121 @@ "hash.js": "1.1.7" } }, + "@ethersproject/signing-key": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/@ethersproject/signing-key/-/signing-key-5.6.0.tgz", + "integrity": "sha512-S+njkhowmLeUu/r7ir8n78OUKx63kBdMCPssePS89So1TH4hZqnWFsThEd/GiXYp9qMxVrydf7KdM9MTGPFukA==", + "requires": { + "@ethersproject/bytes": "^5.6.0", + "@ethersproject/logger": "^5.6.0", + "@ethersproject/properties": "^5.6.0", + "bn.js": "^4.11.9", + "elliptic": "6.5.4", + "hash.js": "1.1.7" + }, + "dependencies": { + "bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + } + } + }, + "@ethersproject/solidity": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/@ethersproject/solidity/-/solidity-5.6.0.tgz", + "integrity": "sha512-YwF52vTNd50kjDzqKaoNNbC/r9kMDPq3YzDWmsjFTRBcIF1y4JCQJ8gB30wsTfHbaxgxelI5BfxQSxD/PbJOww==", + "requires": { + "@ethersproject/bignumber": "^5.6.0", + "@ethersproject/bytes": "^5.6.0", + "@ethersproject/keccak256": "^5.6.0", + "@ethersproject/logger": "^5.6.0", + "@ethersproject/sha2": "^5.6.0", + "@ethersproject/strings": "^5.6.0" + } + }, + "@ethersproject/strings": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/@ethersproject/strings/-/strings-5.6.0.tgz", + "integrity": "sha512-uv10vTtLTZqrJuqBZR862ZQjTIa724wGPWQqZrofaPI/kUsf53TBG0I0D+hQ1qyNtllbNzaW+PDPHHUI6/65Mg==", + "requires": { + "@ethersproject/bytes": "^5.6.0", + "@ethersproject/constants": "^5.6.0", + "@ethersproject/logger": "^5.6.0" + } + }, + "@ethersproject/transactions": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/@ethersproject/transactions/-/transactions-5.6.0.tgz", + "integrity": "sha512-4HX+VOhNjXHZyGzER6E/LVI2i6lf9ejYeWD6l4g50AdmimyuStKc39kvKf1bXWQMg7QNVh+uC7dYwtaZ02IXeg==", + "requires": { + "@ethersproject/address": "^5.6.0", + "@ethersproject/bignumber": "^5.6.0", + "@ethersproject/bytes": "^5.6.0", + "@ethersproject/constants": "^5.6.0", + "@ethersproject/keccak256": "^5.6.0", + "@ethersproject/logger": "^5.6.0", + "@ethersproject/properties": "^5.6.0", + "@ethersproject/rlp": "^5.6.0", + "@ethersproject/signing-key": "^5.6.0" + } + }, + "@ethersproject/units": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/@ethersproject/units/-/units-5.6.0.tgz", + "integrity": "sha512-tig9x0Qmh8qbo1w8/6tmtyrm/QQRviBh389EQ+d8fP4wDsBrJBf08oZfoiz1/uenKK9M78yAP4PoR7SsVoTjsw==", + "requires": { + "@ethersproject/bignumber": "^5.6.0", + "@ethersproject/constants": "^5.6.0", + "@ethersproject/logger": "^5.6.0" + } + }, + "@ethersproject/wallet": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/@ethersproject/wallet/-/wallet-5.6.0.tgz", + "integrity": "sha512-qMlSdOSTyp0MBeE+r7SUhr1jjDlC1zAXB8VD84hCnpijPQiSNbxr6GdiLXxpUs8UKzkDiNYYC5DRI3MZr+n+tg==", + "requires": { + "@ethersproject/abstract-provider": "^5.6.0", + "@ethersproject/abstract-signer": "^5.6.0", + "@ethersproject/address": "^5.6.0", + "@ethersproject/bignumber": "^5.6.0", + "@ethersproject/bytes": "^5.6.0", + "@ethersproject/hash": "^5.6.0", + "@ethersproject/hdnode": "^5.6.0", + "@ethersproject/json-wallets": "^5.6.0", + "@ethersproject/keccak256": "^5.6.0", + "@ethersproject/logger": "^5.6.0", + "@ethersproject/properties": "^5.6.0", + "@ethersproject/random": "^5.6.0", + "@ethersproject/signing-key": "^5.6.0", + "@ethersproject/transactions": "^5.6.0", + "@ethersproject/wordlists": "^5.6.0" + } + }, + "@ethersproject/web": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/@ethersproject/web/-/web-5.6.0.tgz", + "integrity": "sha512-G/XHj0hV1FxI2teHRfCGvfBUHFmU+YOSbCxlAMqJklxSa7QMiHFQfAxvwY2PFqgvdkxEKwRNr/eCjfAPEm2Ctg==", + "requires": { + "@ethersproject/base64": "^5.6.0", + "@ethersproject/bytes": "^5.6.0", + "@ethersproject/logger": "^5.6.0", + "@ethersproject/properties": "^5.6.0", + "@ethersproject/strings": "^5.6.0" + } + }, + "@ethersproject/wordlists": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/@ethersproject/wordlists/-/wordlists-5.6.0.tgz", + "integrity": "sha512-q0bxNBfIX3fUuAo9OmjlEYxP40IB8ABgb7HjEZCL5IKubzV3j30CWi2rqQbjTS2HfoyQbfINoKcTVWP4ejwR7Q==", + "requires": { + "@ethersproject/bytes": "^5.6.0", + "@ethersproject/hash": "^5.6.0", + "@ethersproject/logger": "^5.6.0", + "@ethersproject/properties": "^5.6.0", + "@ethersproject/strings": "^5.6.0" + } + }, "@humanwhocodes/config-array": { "version": "0.5.0", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.5.0.tgz", @@ -3106,6 +4433,14 @@ "integrity": "sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA==", "dev": true }, + "@types/bn.js": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@types/bn.js/-/bn.js-5.1.0.tgz", + "integrity": "sha512-QSSVYj7pYFN49kW77o2s9xTCwZ8F2xLbjLLSEVh8D2F4JUhZtPAGOFLTD+ffqksBx/u4cE/KImFjyhqCjn/LIA==", + "requires": { + "@types/node": "*" + } + }, "@types/connect": { "version": "3.4.35", "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz", @@ -3139,6 +4474,14 @@ "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.29.tgz", "integrity": "sha512-tx5jMmMFwx7wBwq/V7OohKDVb/JwJU5qCVkeLMh1//xycAJ/ESuw9aJ9SEtlCZDYi2pBfe4JkisSoAtbOsBNAA==" }, + "@types/pbkdf2": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@types/pbkdf2/-/pbkdf2-3.1.0.tgz", + "integrity": "sha512-Cf63Rv7jCQ0LaL8tNXmEyqTHuIJxRdlS5vMh1mj5voN4+QFhVZnlZruezqpWYDiJ8UTzhP0VmeLXCmBk66YrMQ==", + "requires": { + "@types/node": "*" + } + }, "@types/qs": { "version": "6.9.7", "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz", @@ -3149,6 +4492,14 @@ "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.4.tgz", "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==" }, + "@types/secp256k1": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@types/secp256k1/-/secp256k1-4.0.3.tgz", + "integrity": "sha512-Da66lEIFeIz9ltsdMZcpQvmrmmoqrfju8pm1BH8WbYjZSwUgCwXLb9C+9XYogwBITnbsSaMdVPb2ekf7TV+03w==", + "requires": { + "@types/node": "*" + } + }, "@types/ws": { "version": "7.4.7", "resolved": "https://registry.npmjs.org/@types/ws/-/ws-7.4.7.tgz", @@ -3191,6 +4542,11 @@ "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", "dev": true }, + "aes-js": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/aes-js/-/aes-js-3.0.0.tgz", + "integrity": "sha1-4h3xCtbCBTKVvLuNq0Cwnb6ofk0=" + }, "ajv": { "version": "6.12.6", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", @@ -3326,6 +4682,11 @@ } } }, + "blakejs": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/blakejs/-/blakejs-1.2.1.tgz", + "integrity": "sha512-QXUSXI3QVc/gJME0dBpXrag1kbzOqCjCX8/b54ntNyW6sjtoqxqRk3LTmXzaJoh71zMsDCjM+47jS7XiwN/+fQ==" + }, "bn.js": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.0.tgz", @@ -3360,6 +4721,19 @@ "resolved": "https://registry.npmjs.org/browser-headers/-/browser-headers-0.4.1.tgz", "integrity": "sha512-CA9hsySZVo9371qEHjHZtYxV2cFtVj5Wj/ZHi8ooEsrtm4vOnl9Y9HmyYWk9q+05d7K3rdoAE0j3MVEFVvtQtg==" }, + "browserify-aes": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", + "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", + "requires": { + "buffer-xor": "^1.0.3", + "cipher-base": "^1.0.0", + "create-hash": "^1.1.0", + "evp_bytestokey": "^1.0.3", + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, "bs58": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/bs58/-/bs58-4.0.1.tgz", @@ -3392,6 +4766,11 @@ "resolved": "https://registry.npmjs.org/buffer-layout/-/buffer-layout-1.2.2.tgz", "integrity": "sha512-kWSuLN694+KTk8SrYvCqwP2WcgQjoRCiF5b4QDvkkz8EmgD+aWAIceGFKMIAdmF/pH+vpgNV3d3kAKorcdAmWA==" }, + "buffer-xor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", + "integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=" + }, "bufferutil": { "version": "4.0.6", "resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-4.0.6.tgz", @@ -3764,11 +5143,115 @@ "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", "dev": true }, + "ethereum-bloom-filters": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/ethereum-bloom-filters/-/ethereum-bloom-filters-1.0.10.tgz", + "integrity": "sha512-rxJ5OFN3RwjQxDcFP2Z5+Q9ho4eIdEmSc2ht0fCu8Se9nbXjZ7/031uXoUYJ87KHCOdVeiUuwSnoS7hmYAGVHA==", + "requires": { + "js-sha3": "^0.8.0" + } + }, + "ethereum-cryptography": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", + "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==", + "requires": { + "@types/pbkdf2": "^3.0.0", + "@types/secp256k1": "^4.0.1", + "blakejs": "^1.1.0", + "browserify-aes": "^1.2.0", + "bs58check": "^2.1.2", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "hash.js": "^1.1.7", + "keccak": "^3.0.0", + "pbkdf2": "^3.0.17", + "randombytes": "^2.1.0", + "safe-buffer": "^5.1.2", + "scrypt-js": "^3.0.0", + "secp256k1": "^4.0.1", + "setimmediate": "^1.0.5" + } + }, + "ethereumjs-util": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-7.1.4.tgz", + "integrity": "sha512-p6KmuPCX4mZIqsQzXfmSx9Y0l2hqf+VkAiwSisW3UKUFdk8ZkAt+AYaor83z2nSi6CU2zSsXMlD80hAbNEGM0A==", + "requires": { + "@types/bn.js": "^5.1.0", + "bn.js": "^5.1.2", + "create-hash": "^1.1.2", + "ethereum-cryptography": "^0.1.3", + "rlp": "^2.2.4" + } + }, + "ethers": { + "version": "5.6.4", + "resolved": "https://registry.npmjs.org/ethers/-/ethers-5.6.4.tgz", + "integrity": "sha512-62UIfxAQXdf67TeeOaoOoPctm5hUlYgfd0iW3wxfj7qRYKDcvvy0f+sJ3W2/Pyx77R8dblvejA8jokj+lS+ATQ==", + "requires": { + "@ethersproject/abi": "5.6.1", + "@ethersproject/abstract-provider": "5.6.0", + "@ethersproject/abstract-signer": "5.6.0", + "@ethersproject/address": "5.6.0", + "@ethersproject/base64": "5.6.0", + "@ethersproject/basex": "5.6.0", + "@ethersproject/bignumber": "5.6.0", + "@ethersproject/bytes": "5.6.1", + "@ethersproject/constants": "5.6.0", + "@ethersproject/contracts": "5.6.0", + "@ethersproject/hash": "5.6.0", + "@ethersproject/hdnode": "5.6.0", + "@ethersproject/json-wallets": "5.6.0", + "@ethersproject/keccak256": "5.6.0", + "@ethersproject/logger": "5.6.0", + "@ethersproject/networks": "5.6.2", + "@ethersproject/pbkdf2": "5.6.0", + "@ethersproject/properties": "5.6.0", + "@ethersproject/providers": "5.6.4", + "@ethersproject/random": "5.6.0", + "@ethersproject/rlp": "5.6.0", + "@ethersproject/sha2": "5.6.0", + "@ethersproject/signing-key": "5.6.0", + "@ethersproject/solidity": "5.6.0", + "@ethersproject/strings": "5.6.0", + "@ethersproject/transactions": "5.6.0", + "@ethersproject/units": "5.6.0", + "@ethersproject/wallet": "5.6.0", + "@ethersproject/web": "5.6.0", + "@ethersproject/wordlists": "5.6.0" + } + }, + "ethjs-unit": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/ethjs-unit/-/ethjs-unit-0.1.6.tgz", + "integrity": "sha1-xmWSHkduh7ziqdWIpv4EBbLEFpk=", + "requires": { + "bn.js": "4.11.6", + "number-to-bn": "1.7.0" + }, + "dependencies": { + "bn.js": { + "version": "4.11.6", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.6.tgz", + "integrity": "sha1-UzRK2xRhehP26N0s4okF0cC6MhU=" + } + } + }, "eventemitter3": { "version": "4.0.7", "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==" }, + "evp_bytestokey": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", + "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", + "requires": { + "md5.js": "^1.3.4", + "safe-buffer": "^5.1.1" + } + }, "eyes": { "version": "0.1.8", "resolved": "https://registry.npmjs.org/eyes/-/eyes-0.1.8.tgz", @@ -3975,6 +5458,11 @@ "is-extglob": "^2.1.1" } }, + "is-hex-prefixed": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-hex-prefixed/-/is-hex-prefixed-1.0.0.tgz", + "integrity": "sha1-fY035q135dEnFIkTxXPggtd39VQ=" + }, "isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", @@ -4078,6 +5566,16 @@ "through": ">=2.2.7 <3" } }, + "keccak": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/keccak/-/keccak-3.0.2.tgz", + "integrity": "sha512-PyKKjkH53wDMLGrvmRGSNWgmSxZOUqbnXwKL9tmgbFYA1iAYqW21kfR7mZXV0MlESiefxQQE9X9fTa3X+2MPDQ==", + "requires": { + "node-addon-api": "^2.0.0", + "node-gyp-build": "^4.2.0", + "readable-stream": "^3.6.0" + } + }, "levn": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", @@ -4188,6 +5686,22 @@ "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.4.0.tgz", "integrity": "sha512-amJnQCcgtRVw9SvoebO3BKGESClrfXGCUTX9hSn1OuGQTQBOZmVd0Z0OlecpuRksKvbsUqALE8jls/ErClAPuQ==" }, + "number-to-bn": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/number-to-bn/-/number-to-bn-1.7.0.tgz", + "integrity": "sha1-uzYjWS9+X54AMLGXe9QaDFP+HqA=", + "requires": { + "bn.js": "4.11.6", + "strip-hex-prefix": "1.0.0" + }, + "dependencies": { + "bn.js": { + "version": "4.11.6", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.6.tgz", + "integrity": "sha1-UzRK2xRhehP26N0s4okF0cC6MhU=" + } + } + }, "once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -4348,6 +5862,14 @@ "inherits": "^2.0.1" } }, + "rlp": { + "version": "2.2.7", + "resolved": "https://registry.npmjs.org/rlp/-/rlp-2.2.7.tgz", + "integrity": "sha512-d5gdPmgQ0Z+AklL2NVXr/IoSjNZFfTVvQWzL/AM2AOcSzYP2xjlb0AC8YyCLc41MSNf6P6QVtjgPdmVtzb+4lQ==", + "requires": { + "bn.js": "^5.2.0" + } + }, "rpc-websockets": { "version": "7.4.18", "resolved": "https://registry.npmjs.org/rpc-websockets/-/rpc-websockets-7.4.18.tgz", @@ -4382,6 +5904,11 @@ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" }, + "scrypt-js": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/scrypt-js/-/scrypt-js-3.0.1.tgz", + "integrity": "sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA==" + }, "secp256k1": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/secp256k1/-/secp256k1-4.0.3.tgz", @@ -4401,6 +5928,11 @@ "lru-cache": "^6.0.0" } }, + "setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=" + }, "sha.js": { "version": "2.4.11", "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", @@ -4468,6 +6000,14 @@ "ansi-regex": "^5.0.1" } }, + "strip-hex-prefix": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-hex-prefix/-/strip-hex-prefix-1.0.0.tgz", + "integrity": "sha1-DF8VX+8RUTczd96du1iNoFUA428=", + "requires": { + "is-hex-prefixed": "1.0.0" + } + }, "strip-json-comments": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", @@ -4656,6 +6196,11 @@ "node-gyp-build": "^4.3.0" } }, + "utf8": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/utf8/-/utf8-3.0.0.tgz", + "integrity": "sha512-E8VjFIQ/TyQgp+TZfS6l8yp/xWppSAHzidGiRrqe4bK4XP9pTRyKFgGJpO3SN7zdX4DeomTrwaseCHovfpFcqQ==" + }, "util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -4678,6 +6223,54 @@ "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", "dev": true }, + "web3-eth-abi": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/web3-eth-abi/-/web3-eth-abi-1.7.3.tgz", + "integrity": "sha512-ZlD8DrJro0ocnbZViZpAoMX44x5aYAb73u2tMq557rMmpiluZNnhcCYF/NnVMy6UIkn7SF/qEA45GXA1ne6Tnw==", + "requires": { + "@ethersproject/abi": "5.0.7", + "web3-utils": "1.7.3" + }, + "dependencies": { + "@ethersproject/abi": { + "version": "5.0.7", + "resolved": "https://registry.npmjs.org/@ethersproject/abi/-/abi-5.0.7.tgz", + "integrity": "sha512-Cqktk+hSIckwP/W8O47Eef60VwmoSC/L3lY0+dIBhQPCNn9E4V7rwmm2aFrNRRDJfFlGuZ1khkQUOc3oBX+niw==", + "requires": { + "@ethersproject/address": "^5.0.4", + "@ethersproject/bignumber": "^5.0.7", + "@ethersproject/bytes": "^5.0.4", + "@ethersproject/constants": "^5.0.4", + "@ethersproject/hash": "^5.0.4", + "@ethersproject/keccak256": "^5.0.3", + "@ethersproject/logger": "^5.0.5", + "@ethersproject/properties": "^5.0.3", + "@ethersproject/strings": "^5.0.4" + } + } + } + }, + "web3-utils": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/web3-utils/-/web3-utils-1.7.3.tgz", + "integrity": "sha512-g6nQgvb/bUpVUIxJE+ezVN+rYwYmlFyMvMIRSuqpi1dk6ApDD00YNArrk7sPcZnjvxOJ76813Xs2vIN2rgh4lg==", + "requires": { + "bn.js": "^4.11.9", + "ethereum-bloom-filters": "^1.0.6", + "ethereumjs-util": "^7.1.0", + "ethjs-unit": "0.1.6", + "number-to-bn": "1.7.0", + "randombytes": "^2.1.0", + "utf8": "3.0.0" + }, + "dependencies": { + "bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + } + } + }, "webidl-conversions": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", diff --git a/terra/scripts/package.json b/terra/scripts/package.json index 964c9b1f..7c81b531 100644 --- a/terra/scripts/package.json +++ b/terra/scripts/package.json @@ -14,8 +14,11 @@ "bignumber.js": "^9.0.1", "dotenv": "^8.2.0", "elliptic": "^6.5.4", + "ethers": "^5.6.4", "prettier": "^2.6.1", "ts-custom-error": "^3.2.0", + "web3-eth-abi": "^1.7.3", + "web3-utils": "^1.7.3", "yargs": "^17.4.1" }, "devDependencies": { diff --git a/terra/scripts/tests/README.md b/terra/scripts/tests/README.md index 0b9615fc..1dc8e442 100644 --- a/terra/scripts/tests/README.md +++ b/terra/scripts/tests/README.md @@ -6,24 +6,38 @@ This is a work-in-progress. Tests will cover the following scenarios in `contributor.ts` (see [whitepaper](../../../WHITEPAPER.md) for details on how the Contributor works). +### Preparation + +- [x] Mint CW20 Mock Token +- [x] Query Balance of Mock Token + ### Deployment - [x] Deploy Contract -- [ ] Expect Error when Non-Owner Attempts to Upgrade Contract +- [ ] Non-Owner Cannot Upgrade Contract - [ ] Upgrade Contract ### Conduct Successful Sale -- [ ] Orchestrator Initializes Sale -- [ ] User Contributes to Sale -- [ ] Orchestrator Attests Contributions -- [ ] Orchestrator Seals Sale -- [ ] User Claims Allocations +- [x] 1. Orchestrator Initializes Sale +- [x] 2. Orchestrator Cannot Intialize Sale Again +- [x] 3. User Contributes to Sale (Native) +- [x] 4. User Contributes to Sale (CW20) +- [x] 5. User Cannot Contribute for Non-existent Token Index +- [x] 6. Orchestrator Cannot Attest Contributions Too Early +- [x] 7. User Cannot Contribute After Sale Ended +- [x] 8. Orchestrator Attests Contributions +- [ ] 9. Orchestrator Seals Sale +- [ ] 10. Orchestrator Cannot Seal Sale Again +- [ ] 11. User Claims Allocations +- [ ] 12. User Cannot Claim Allocations Again ### Conduct Aborted Sale -- [ ] Orchestrator Initializes Sale -- [ ] User Contributes to Sale -- [ ] Orchestrator Attests Contributions -- [ ] Orchestrator Aborts Sale -- [ ] User Claims Refunds +- [x] 1. Orchestrator Initializes Sale +- [x] 2. User Contributes to Sale (Native) +- [x] 3. User Contributes to Sale (CW20) +- [ ] 4. Orchestrator Aborts Sale +- [ ] 5. Orchestrator Cannot Abort Sale Again +- [ ] 6. User Claims Refunds +- [ ] 7. User Cannot Claims Refunds Again diff --git a/terra/scripts/tests/contributor.ts b/terra/scripts/tests/contributor.ts index 2dd64682..0416b7e4 100644 --- a/terra/scripts/tests/contributor.ts +++ b/terra/scripts/tests/contributor.ts @@ -1,30 +1,957 @@ -import { LCDClient, Wallet } from "@terra-money/terra.js"; +import { BlockTxBroadcastResult, Coin, Coins, Int, LCDClient, Wallet } from "@terra-money/terra.js"; +import { nativeToHexString, CHAIN_ID_TERRA } from "@certusone/wormhole-sdk"; + import { WORMHOLE_ADDRESSES } from "../consts"; import { instantiateContract, - newLocalClient, + executeContract, uploadContract, + queryContract, + sleep, } from "../helpers"; +import { + CONDUCTOR_CHAIN, + CONDUCTOR_ADDRESS, + AcceptedToken, + encodeSaleInit, + getBlockTime, + signAndEncodeConductorVaa, + getErrorMessage, + getBalance, + makeClientAndWallets, + getBuyerStatus, + getTotalContribution, + encodeSaleAborted, +} from "./lib"; + const contracts = new Map(); async function main() { - const { terra, wallet } = newLocalClient(); + // real test here + //const { terra, wallet } = newLocalClient(); + const [terra, actors] = makeClientAndWallets(); + + console.log("-------- Preparation --------\n"); + await mintCw20(terra, actors.owner, actors.buyers); + console.log(); console.log("-------- Deployment --------\n"); - await deployment(terra, wallet); + await deployment(terra, actors.owner, actors.seller); console.log(); console.log("-------- Conduct Successful Sale --------\n"); - await conductSuccessfulSale(terra, wallet); + await conductSuccessfulSale(terra, actors.seller, actors.buyers); console.log(); console.log("-------- Conduct Aborted Sale --------\n"); - await conductAbortedSale(terra, wallet); + await conductAbortedSale(terra, actors.seller, actors.buyers); console.log(); return; } +async function mintCw20(terra: LCDClient, owner: Wallet, buyers: Wallet[]): Promise { + const mintAmount = "1000000000000"; // 1,000,000.000000 + + { + logTestName("1. Mint CW20 Test token"); + + const cw20CodeId = 4; // cw20_base (from wormhole contract deployments) + const msg: any = { + name: "Definitely Worth Something", + symbol: "WORTH", + decimals: 6, + initial_balances: [ + { + address: owner.key.accAddress, + amount: mintAmount, + }, + { + address: buyers[0].key.accAddress, + amount: mintAmount, + }, + { + address: buyers[1].key.accAddress, + amount: mintAmount, + }, + ], + mint: null, + }; + const mockToken = await instantiateContract( + terra, + owner, + owner.key.accAddress, + cw20CodeId, + msg + ); + contracts.set("mockToken", mockToken); + logAddr("mockToken", mockToken); + + // done + success(); + } + + { + logTestName("2. Query Balance of Mock Token"); + + const mockToken = contracts.get("mockToken"); + if (mockToken === undefined) { + throw Error("mock token not minted"); + } + + for (const wallet of [owner, buyers[0], buyers[1]]) { + const msg: any = { + balance: { + address: wallet.key.accAddress, + }, + }; + const result = await queryContract(terra, mockToken, msg); + if (result.balance !== mintAmount) { + return failMessage("result.balance !== mintAmount"); + } + } + + success(); + } + + // done + return; +} + +async function deployment(terra: LCDClient, owner: Wallet, another: Wallet): Promise { + { + logTestName("1. Deploy Contract"); + const addresses = WORMHOLE_ADDRESSES.localterra; + + const codeId = await uploadContract(terra, owner, "../artifacts/icco_contributor.wasm"); + + const msg: any = { + wormhole: addresses.wormhole, + token_bridge: addresses.tokenBridge, + conductor_chain: CONDUCTOR_CHAIN, + conductor_address: Buffer.from(CONDUCTOR_ADDRESS, "hex").toString("base64"), + }; + const contributor = await instantiateContract(terra, owner, owner.key.accAddress, codeId, msg); + contracts.set("contributor", contributor); + logAddr("contributor", contributor); + + // done + success(); + } + + { + logTestName("2. Non-Owner Cannot Upgrade Contract"); + untested(); + } + + { + logTestName("3. Upgrade Contract"); + untested(); + } + + // done + return; +} + +async function conductSuccessfulSale( + terra: LCDClient, + seller: Wallet, + buyers: Wallet[] +): Promise { + // get mock token + const mockToken = contracts.get("mockToken"); + if (mockToken === undefined) { + throw Error("mock token not minted yet"); + } + + // get deployed address + const contributor = contracts.get("contributor"); + if (contributor === undefined) { + throw Error("contributor not deployed yet"); + } + + // set up saleInit vaa + const saleId = 1; + const tokenAddress = "00000000000000000000000083752ecafebf4707258dedffbd9c7443148169db"; + const tokenChain = 2; + const tokenAmount = "1000000000000000000"; + const minRaise = "10000000000000000000"; + const maxRaise = "14000000000000000000"; + + // set up sale time based on block time + const blockTime = await getBlockTime(terra); + const saleStart = blockTime + 5; + const saleEnd = blockTime + 35; + + const acceptedTokens: AcceptedToken[] = [ + { + address: nativeToHexString("uluna", CHAIN_ID_TERRA)!, + chain: 3, + conversionRate: "1000000000000000000", + }, + { + address: nativeToHexString(mockToken, CHAIN_ID_TERRA)!, + chain: 3, + conversionRate: "200000000000000000", + }, + ]; + + const recipient = "00000000000000000000000022d491bde2303f2f43325b2108d26f1eaba1e32b"; + const refundRecipient = "00000000000000000000000022d491bde2303f2f43325b2108d26f1eaba1e32b"; + + // save state + const sale: any = {}; + + { + logTestName(" 1. Orchestrator Initializes Sale... "); + // Conductor will have produced a VAA. Here we fabricate the VAA and + // forge a signature with devnet guardian + const data = encodeSaleInit( + saleId, + tokenAddress, + tokenChain, + tokenAmount, + minRaise, + maxRaise, + saleStart, + saleEnd, + acceptedTokens, + recipient, + refundRecipient + ); + + // save the sale id and sale end time + sale.saleId = data.subarray(1, 33); + sale.saleEnd = saleEnd; + + const timestamp = 1; + const nonce = 0; + const sequence = 3; + + const signedVaa = signAndEncodeConductorVaa(timestamp, nonce, sequence, data); + sale.saleInitVaa = signedVaa; + + try { + // ExecuteMsg::InitSale { signed_vaa } + const msg: any = { + init_sale: { + signed_vaa: signedVaa.toString("base64"), + }, + }; + + const receipt = await executeContract( + //terra, + seller, + contributor, + msg + ); + logTx("InitSale", receipt); + } catch (e: any) { + return fail(e); + } + + // done + success(); + } + + { + logTestName(" 2. Orchestrator Cannot Intialize Sale Again"); + const signedVaa = sale.saleInitVaa; + + let failed = false; + try { + // ExecuteMsg::InitSale { signed_vaa } + const msg: any = { + init_sale: { + signed_vaa: signedVaa.toString("base64"), + }, + }; + + const receipt = await executeContract( + //terra, + seller, + contributor, + msg + ); + logTx("InitSale", receipt); + failed = receipt.raw_log.includes("SaleAlreadyExists"); + } catch (e: any) { + failed = getErrorMessage(e).includes("SaleAlreadyExists"); + } + + if (!failed) { + return successUnexpected(); + } + + // done + success(); + } + + { + logTestName(" 3. User Contributes to Sale (Native)"); + + const denom = "uluna"; + const contributorBalanceBefore = await getBalance(terra, denom, contributor); + const walletBalanceBefore = await getBalance(terra, denom, buyers[0].key.accAddress); + + const tokenIndex = 0; + const amounts = ["1000000", "2000000"]; + const totalAmount = amounts + .map((x: string) => new Int(x)!) + .reduce((x: Int, y: Int) => x.add(y) as Int) + .toString(); + + // save to verify attest contribution + sale.denomTotalAmount = totalAmount; + + // contribute twice + try { + for (const amount of amounts) { + // ExecuteMsg::Contribute { sale_id, token_index, amount } + const msg: any = { + contribute: { + sale_id: sale.saleId.toString("base64"), + token_index: tokenIndex, + amount, + }, + }; + const receipt = await executeContract( + //terra, + buyers[0], + contributor, + msg, + new Coins([new Coin(denom, amount)]) + ); + logTx("Contribute", receipt); + } + } catch (e: any) { + return fail(e); + } + + // double-check native balance + { + const contributorBalance = await getBalance(terra, denom, contributor); + if ( + contributorBalance.lte(contributorBalanceBefore) || + !contributorBalance.sub(contributorBalanceBefore).equals(totalAmount) + ) { + return failMessage("contributor balance change !== totalAmount"); + } + + const walletBalance = await getBalance(terra, denom, buyers[0].key.accAddress); + if ( + walletBalance.gte(walletBalanceBefore) || + !walletBalanceBefore.sub(walletBalance).equals(totalAmount) + ) { + return failMessage("wallet balance change !== totalAmount"); + } + } + + // query buyer's contribution + { + const status = await getBuyerStatus( + terra, + contributor, + sale.saleId, + tokenIndex, + buyers[0].key.accAddress + ); + if (!status.active || status.active.contribution != totalAmount) { + return failMessage(`wrong buyer status: ${status}`); + } + } + + // query total contributions + { + const totalContribution = await getTotalContribution( + terra, + contributor, + sale.saleId, + tokenIndex + ); + if (!totalContribution.equals(totalAmount)) { + return failMessage(`wrong total contribution: ${totalContribution} vs ${totalAmount}`); + } + } + + // done + success(); + } + + { + logTestName(" 4. User Contributes to Sale (CW20)"); + + const contributorBalanceBefore = await getBalance(terra, mockToken, contributor); + const walletBalanceBefore = await getBalance(terra, mockToken, buyers[0].key.accAddress); + + const tokenIndex = 1; + const amounts = ["2000000", "3000000"]; + const totalAmount = amounts + .map((x: string) => new Int(x)!) + .reduce((x: Int, y: Int) => x.add(y) as Int) + .toString(); + + // save to verify attest contribution + sale.tokenTotalAmount = totalAmount; + + // set allowance for total + try { + { + const msg: any = { + increase_allowance: { + spender: contributor, + amount: totalAmount, + expires: { + never: {}, + }, + }, + }; + const receipt = await executeContract( + //terra, + buyers[0], + mockToken, + msg + ); + logTx("IncreaseAllowance", receipt); + } + } catch (e: any) { + return fail(e); + } + + // contribute twice + try { + for (const amount of amounts) { + // ExecuteMsg::Contribute { sale_id, token_index, amount } + const msg = { + contribute: { + sale_id: sale.saleId.toString("base64"), + token_index: tokenIndex, + amount, + }, + }; + const receipt = await executeContract( + //terra, + buyers[0], + contributor, + msg + ); + logTx("Contribute", receipt); + } + } catch (e: any) { + return fail(e); + } + + // double-check cw20 balance on wallet and contract + { + const contributorBalance = await getBalance(terra, mockToken, contributor); + if ( + contributorBalance.lte(contributorBalanceBefore) || + !contributorBalance.sub(contributorBalanceBefore).equals(totalAmount) + ) { + return failMessage("contributor balance change !== totalAmount"); + } + + const walletBalance = await getBalance(terra, mockToken, buyers[0].key.accAddress); + if ( + walletBalance.gte(walletBalanceBefore) || + !walletBalanceBefore.sub(walletBalance).equals(totalAmount) + ) { + return failMessage("wallet balance change !== totalAmount"); + } + } + + // query buyer's contribution + { + const status = await getBuyerStatus( + terra, + contributor, + sale.saleId, + tokenIndex, + buyers[0].key.accAddress + ); + if (!status.active || status.active.contribution != totalAmount) { + return failMessage(`wrong buyer status: ${status}`); + } + } + + // query total contributions + { + const totalContribution = await getTotalContribution( + terra, + contributor, + sale.saleId, + tokenIndex + ); + if (!totalContribution.equals(totalAmount)) { + return failMessage(`wrong total contribution: ${totalContribution} vs ${totalAmount}`); + } + } + + // done + success(); + } + + { + logTestName(" 5. User Cannot Contribute for Nonexistent Token Index"); + + // dafuq + let failed = false; + try { + const badTokenIndex = 2; + const denom = "uluna"; + const amount = "42069"; + + // ExecuteMsg::Contribute { sale_id, token_index, amount } + const msg: any = { + contribute: { + sale_id: sale.saleId.toString("base64"), + token_index: badTokenIndex, + amount, + }, + }; + const receipt = await executeContract( + //terra, + buyers[0], + contributor, + msg, + new Coins([new Coin(denom, amount)]) + ); + logTx("Contribute", receipt); + failed = receipt.raw_log.includes("AssetInfo not found"); + } catch (e: any) { + failed = getErrorMessage(e).includes("AssetInfo not found"); + } + + if (!failed) { + return successUnexpected(); + } + + // done + success(); + } + + { + logTestName(" 6. Orchestrator Cannot Attest Contributions Too Early"); + + let failed = false; + try { + const msg: any = { + attest_contributions: { + sale_id: sale.saleId.toString("base64"), + }, + }; + const receipt = await executeContract(seller, contributor, msg); + logTx("AttestContributions", receipt); + failed = receipt.raw_log.includes("SaleNotFinished"); + } catch (e: any) { + failed = getErrorMessage(e).includes("SaleNotFinished"); + } + + if (!failed) { + return successUnexpected(); + } + + // done + success(); + } + + // and we wait for the sale to end + { + const blockTime = await getBlockTime(terra); + if (blockTime < sale.saleEnd) { + const remaining = sale.saleEnd - blockTime + 2; // need a little buffer + console.log(`waiting ${remaining} seconds for sale to end`); + + await sleep(remaining * 1000); + } + } + + { + logTestName(" 7. User Cannot Contribute After Sale Ended"); + + let failed = false; + try { + const denom = "uluna"; + const amount = "42069"; + + // ExecuteMsg::Contribute { sale_id, token_index, amount } + const msg: any = { + contribute: { + sale_id: sale.saleId.toString("base64"), + token_index: 0, + amount, + }, + }; + const receipt = await executeContract( + //terra, + buyers[0], + contributor, + msg, + new Coins([new Coin(denom, amount)]) + ); + logTx("Contribute", receipt); + failed = receipt.raw_log.includes("SaleEnded"); + } catch (e: any) { + failed = getErrorMessage(e).includes("SaleEnded"); + } + + if (!failed) { + return successUnexpected(); + } + + // done + success(); + } + + { + logTestName(" 8. Orchestrator Attests Contributions"); + + let log: any = undefined; + + try { + const msg: any = { + attest_contributions: { + sale_id: sale.saleId.toString("base64"), + }, + }; + const receipt = await executeContract(seller, contributor, msg); + logTx("AttestContributions", receipt); + log = receipt.logs[0]; + } catch (e: any) { + return fail(e); + } + + // parse attest contributions to see if info agrees with what we expect + // use total amounts saved in sale + { + // 1 := from_contract + const events = log.events[1].attributes; + // 4 := bytes from wormhole message + const expected = + "02000000000000000000000000000000000000000000000000000000000000000100030100000000000000000000000000000000000000000000000000000000004c4b400000000000000000000000000000000000000000000000000000000000002dc6c0"; + const payload = events[4].value; + if (payload != expected) { + return failMessage("wrong attest contribution payload"); + } + } + + // done + success(); + } + + { + logTestName(" 9. Orchestrator Seals Sale"); + untested(); + } + + { + logTestName("10. Orchestrator Cannot Seal Sale Again"); + untested(); + } + + { + logTestName("11. User Claims Allocations"); + untested(); + } + + { + logTestName("12. User Cannot Claim Allocations Again"); + untested(); + } + + return; +} + +async function conductAbortedSale( + terra: LCDClient, + seller: Wallet, + buyers: Wallet[] +): Promise { + // get mock token + const mockToken = contracts.get("mockToken"); + if (mockToken === undefined) { + throw Error("mock token not minted yet"); + } + + // get deployed address + const contributor = contracts.get("contributor"); + if (contributor === undefined) { + throw Error("contributor not deployed yet"); + } + + // set up saleInit vaa + const saleId = 2; + const tokenAddress = "00000000000000000000000083752ecafebf4707258dedffbd9c7443148169db"; + const tokenChain = 2; + const tokenAmount = "1000000000000000000"; + const minRaise = "10000000000000000000"; + const maxRaise = "14000000000000000000"; + + // set up sale time based on block time + const blockTime = await getBlockTime(terra); + const saleStart = blockTime + 5; + const saleEnd = blockTime + 60; + + const acceptedTokens: AcceptedToken[] = [ + { + address: nativeToHexString("uluna", CHAIN_ID_TERRA)!, + chain: 3, + conversionRate: "1000000000000000000", + }, + { + address: nativeToHexString(mockToken, CHAIN_ID_TERRA)!, + chain: 3, + conversionRate: "200000000000000000", + }, + ]; + + const recipient = "00000000000000000000000022d491bde2303f2f43325b2108d26f1eaba1e32b"; + const refundRecipient = "00000000000000000000000022d491bde2303f2f43325b2108d26f1eaba1e32b"; + + // save state + const sale: any = {}; + + { + logTestName(" 1. Orchestrator Initializes Sale... "); + // Conductor will have produced a VAA. Here we fabricate the VAA and + // forge a signature with devnet guardian + const data = encodeSaleInit( + saleId, + tokenAddress, + tokenChain, + tokenAmount, + minRaise, + maxRaise, + saleStart, + saleEnd, + acceptedTokens, + recipient, + refundRecipient + ); + + // save the sale id and sale end time + sale.saleId = data.subarray(1, 33); + sale.saleEnd = saleEnd; + + const timestamp = 1; + const nonce = 2; + const sequence = 3; + + const signedVaa = signAndEncodeConductorVaa(timestamp, nonce, sequence, data); + + try { + // ExecuteMsg::InitSale { signed_vaa } + const msg: any = { + init_sale: { + signed_vaa: signedVaa.toString("base64"), + }, + }; + + const receipt = await executeContract( + //terra, + seller, + contributor, + msg + ); + logTx("InitSale", receipt); + } catch (e: any) { + return fail(e); + } + + // done + success(); + } + + { + logTestName("2. User Contributes to Sale (Native)"); + + const denom = "uluna"; + + const tokenIndex = 0; + const amounts = ["1000000", "2000000"]; + const totalAmount = amounts + .map((x: string) => new Int(x)!) + .reduce((x: Int, y: Int) => x.add(y) as Int) + .toString(); + + // save to verify refund + sale.denomTotalAmount = totalAmount; + + // contribute twice + try { + for (const amount of amounts) { + // ExecuteMsg::Contribute { sale_id, token_index, amount } + const msg: any = { + contribute: { + sale_id: sale.saleId.toString("base64"), + token_index: tokenIndex, + amount, + }, + }; + const receipt = await executeContract( + //terra, + buyers[0], + contributor, + msg, + new Coins([new Coin(denom, amount)]) + ); + logTx("Contribute", receipt); + } + } catch (e: any) { + return fail(e); + } + + // will not check balances and storage like in successful sale + + // done + success(); + } + + { + logTestName(" 3. User Contributes to Sale (CW20)"); + + const tokenIndex = 1; + const amounts = ["2000000", "3000000"]; + const totalAmount = amounts + .map((x: string) => new Int(x)!) + .reduce((x: Int, y: Int) => x.add(y) as Int) + .toString(); + + // save to verify refund + sale.tokenTotalAmount = totalAmount; + + // set allowance for total + try { + { + const msg: any = { + increase_allowance: { + spender: contributor, + amount: totalAmount, + expires: { + never: {}, + }, + }, + }; + const receipt = await executeContract( + //terra, + buyers[0], + mockToken, + msg + ); + logTx("IncreaseAllowance", receipt); + } + } catch (e: any) { + return fail(e); + } + + // contribute twice + try { + for (const amount of amounts) { + // ExecuteMsg::Contribute { sale_id, token_index, amount } + const msg = { + contribute: { + sale_id: sale.saleId.toString("base64"), + token_index: tokenIndex, + amount, + }, + }; + const receipt = await executeContract( + //terra, + buyers[0], + contributor, + msg + ); + logTx("Contribute", receipt); + } + } catch (e: any) { + return fail(e); + } + + // will not check balances and storage like in successful sale + + // done + success(); + } + + { + logTestName("4. Orchestrator Aborts Sale"); + const data = encodeSaleAborted(saleId); + + const timestamp = 2; + const nonce = 0; + const sequence = 4; + + const signedVaa = signAndEncodeConductorVaa(timestamp, nonce, sequence, data); + sale.saleAbortedVaa = signedVaa; + + try { + // ExecuteMsg::SaleAborted { signed_vaa } + const msg: any = { + sale_aborted: { + signed_vaa: signedVaa.toString("base64"), + }, + }; + + const receipt = await executeContract( + //terra, + seller, + contributor, + msg + ); + logTx("SaleAborted", receipt); + } catch (e: any) { + return fail(e); + } + // done + success(); + } + + { + logTestName("5. Orchestrator Cannot Abort Sale Again"); + const signedVaa = sale.saleAbortedVaa; + + let failed = false; + try { + // ExecuteMsg::SaleAborted { signed_vaa } + const msg: any = { + sale_aborted: { + signed_vaa: signedVaa.toString("base64"), + }, + }; + + const receipt = await executeContract( + //terra, + seller, + contributor, + msg + ); + logTx("SaleAborted", receipt); + failed = receipt.raw_log.includes("SaleEnded"); + } catch (e: any) { + failed = getErrorMessage(e).includes("SaleEnded"); + } + + if (!failed) { + return successUnexpected(); + } + + // done + success(); + } + + { + logTestName("6. User Claims Refunds"); + untested(); + } + + { + logTestName("7. User Cannot Claims Refunds Again"); + untested(); + } + + return; +} + function logTestName(test: string): void { console.log("\x1b[33m%s\x1b[0m", test); } @@ -33,113 +960,31 @@ function success(): void { console.log("... \x1b[32msuccess!\x1b[0m"); } +function fail(error: any): void { + //console.log(`... \x1b[41m\x1b[37m${getErrorMessage(error)}\x1b[0m`); + failMessage(getErrorMessage(error)); +} + +function successUnexpected(): void { + failMessage("success unexpected"); +} + +function failMessage(message: string): void { + console.log(`... \x1b[41m\x1b[37m${message}\x1b[0m`); +} + function untested(): void { console.log("... \x1b[31muntested\x1b[0m"); } -async function deployment(terra: LCDClient, wallet: Wallet): Promise { - { - logTestName("1. Deploy Contract"); - const addresses = WORMHOLE_ADDRESSES.localterra; - - const codeId = await uploadContract( - terra, - wallet, - "../artifacts/icco_contributor.wasm" - ); - - const contributor = await instantiateContract( - terra, - wallet, - wallet.key.accAddress, - codeId, - { - wormhole: addresses.wormhole, - token_bridge: addresses.tokenBridge, - conductor_chain: 2, - conductor_address: "", - } - ); - contracts.set("contributor", contributor); - success(); - } - - { - logTestName("2. Upgrade Contract"); - untested(); - } - - // done - return; +function logTx(prefix: string, receipt: BlockTxBroadcastResult): void { + console.log( + `\x1b[36m${prefix}\x1b[0m: https://finder.terra.money/localterra/tx/${receipt.txhash}` + ); } -async function conductSuccessfulSale( - terra: LCDClient, - wallet: Wallet -): Promise { - const sale = {}; - - { - logTestName("1. Orchestrator Initializes Sale... "); - // Conductor will have produced a VAA. Here we fabricate the VAA and - // forge a signature with devnet guardian - - untested(); - } - - { - logTestName("2. User Contributes to Sale"); - untested(); - } - - { - logTestName("3. Orchestrator Attests Contributions"); - untested(); - } - - { - logTestName("4. Orchestrator Seals Sale"); - untested(); - } - - { - logTestName("5. User Claims Allocations"); - untested(); - } - - return; -} - -async function conductAbortedSale( - terra: LCDClient, - wallet: Wallet -): Promise { - { - logTestName("1. Orchestrator Initializes Sale"); - untested(); - } - - { - logTestName("2. User Contributes to Sale"); - untested(); - } - - { - logTestName("3. Orchestrator Attests Contributions"); - untested(); - } - - { - logTestName("4. Orchestrator Aborts Sale"); - untested(); - } - - { - logTestName("5. User Claims Refunds"); - untested(); - } - - return; +function logAddr(prefix: string, addr: string): void { + console.log(`\x1b[36m${prefix}\x1b[0m: https://finder.terra.money/localterra/address/${addr}`); } main(); diff --git a/terra/scripts/tests/lib.ts b/terra/scripts/tests/lib.ts new file mode 100644 index 00000000..ffe870fc --- /dev/null +++ b/terra/scripts/tests/lib.ts @@ -0,0 +1,298 @@ +import { Int, LCDClient, LocalTerra, Wallet } from "@terra-money/terra.js"; +import { BigNumber, BigNumberish } from "ethers"; +import { soliditySha3 } from "web3-utils"; +import { queryContract } from "../helpers"; + +const elliptic = require("elliptic"); + +// sale struct info +const NUM_BYTES_ACCEPTED_TOKEN = 50; +const NUM_BYTES_ALLOCATION = 65; + +// conductor info +export const CONDUCTOR_CHAIN = 2; +export const CONDUCTOR_ADDRESS = "000000000000000000000000f19a2a01b70519f67adb309a994ec8c69a967e8b"; + +export interface Actors { + owner: Wallet; + seller: Wallet; + buyers: Wallet[]; +} + +export function makeClientAndWallets(): [LCDClient, Actors] { + const terra = new LocalTerra(); + const wallets = terra.wallets; + return [ + terra, + { + owner: wallets.test1, + seller: wallets.test2, + buyers: [wallets.test3, wallets.test4], + }, + ]; +} + +export function signAndEncodeConductorVaa( + timestamp: number, + nonce: number, + sequence: number, + data: Buffer +): Buffer { + return signAndEncodeVaaBeta( + //return signAndEncodeVaaLegacy( + timestamp, + nonce, + CONDUCTOR_CHAIN, + CONDUCTOR_ADDRESS, + sequence, + data + ); +} + +export function signAndEncodeVaaBeta( + timestamp: number, + nonce: number, + emitterChainId: number, + emitterAddress: string, + sequence: number, + data: Buffer +): Buffer { + if (Buffer.from(emitterAddress, "hex").length != 32) { + throw Error("emitterAddress != 32 bytes"); + } + + // wormhole initialized with only one guardian in devnet + const signers = ["cfb12303a19cde580bb4dd771639b0d26bc68353645571a8cff516ab2ee113a0"]; + + const sigStart = 6; + const numSigners = signers.length; + const sigLength = 66; + const bodyStart = sigStart + sigLength * numSigners; + const bodyHeaderLength = 51; + const vm = Buffer.alloc(bodyStart + bodyHeaderLength + data.length); + + // header + const guardianSetIndex = 0; + + vm.writeUInt8(1, 0); + vm.writeUInt32BE(guardianSetIndex, 1); + vm.writeUInt8(numSigners, 5); + + // encode body with arbitrary consistency level + const consistencyLevel = 1; + + vm.writeUInt32BE(timestamp, bodyStart); + vm.writeUInt32BE(nonce, bodyStart + 4); + vm.writeUInt16BE(emitterChainId, bodyStart + 8); + vm.write(emitterAddress, bodyStart + 10, "hex"); + vm.writeBigUInt64BE(BigInt(sequence), bodyStart + 42); + vm.writeUInt8(consistencyLevel, bodyStart + 50); + vm.write(data.toString("hex"), bodyStart + bodyHeaderLength, "hex"); + + // signatures + const body = vm.subarray(bodyStart).toString("hex"); + const hash = soliditySha3(soliditySha3("0x" + body)!)!.substring(2); + + for (let i = 0; i < numSigners; ++i) { + const ec = new elliptic.ec("secp256k1"); + const key = ec.keyFromPrivate(signers[i]); + const signature = key.sign(hash, { canonical: true }); + + const start = sigStart + i * sigLength; + vm.writeUInt8(i, start); + vm.write(signature.r.toString(16).padStart(64, "0"), start + 1, "hex"); + vm.write(signature.s.toString(16).padStart(64, "0"), start + 33, "hex"); + vm.writeUInt8(signature.recoveryParam, start + 65); + //console.log(" beta signature", vm.subarray(start, start + 66).toString("hex")); + } + + return vm; +} + +export interface AcceptedToken { + address: string; // 32 bytes + chain: number; // uint16 + conversionRate: string; // uint128 +} + +export function encodeAcceptedTokens(acceptedTokens: AcceptedToken[]): Buffer { + const n = acceptedTokens.length; + const encoded = Buffer.alloc(NUM_BYTES_ACCEPTED_TOKEN * n); + for (let i = 0; i < n; ++i) { + const token = acceptedTokens[i]; + const start = i * NUM_BYTES_ACCEPTED_TOKEN; + encoded.write(token.address, start, "hex"); + encoded.writeUint16BE(token.chain, start + 32); + encoded.write(toBigNumberHex(token.conversionRate, 16), start + 34, "hex"); + } + return encoded; +} + +export function encodeSaleInit( + saleId: number, + tokenAddress: string, // 32 bytes + tokenChain: number, + tokenAmount: string, // uint256 + minRaise: string, // uint256 + maxRaise: string, // uint256 + saleStart: number, + saleEnd: number, + acceptedTokens: AcceptedToken[], // 50 * n_tokens + recipient: string, // 32 bytes + refundRecipient: string // 32 bytes +): Buffer { + const numTokens = acceptedTokens.length; + const encoded = Buffer.alloc(292 + numTokens * NUM_BYTES_ACCEPTED_TOKEN); + + encoded.writeUInt8(1, 0); // initSale payload = 1 + encoded.write(toBigNumberHex(saleId, 32), 1, "hex"); + encoded.write(tokenAddress, 33, "hex"); + encoded.writeUint16BE(tokenChain, 65); + encoded.write(toBigNumberHex(tokenAmount, 32), 67, "hex"); + encoded.write(toBigNumberHex(minRaise, 32), 99, "hex"); + encoded.write(toBigNumberHex(maxRaise, 32), 131, "hex"); + encoded.write(toBigNumberHex(saleStart, 32), 163, "hex"); + encoded.write(toBigNumberHex(saleEnd, 32), 195, "hex"); + encoded.writeUInt8(numTokens, 227); + encoded.write(encodeAcceptedTokens(acceptedTokens).toString("hex"), 228, "hex"); + + const recipientIndex = 228 + numTokens * NUM_BYTES_ACCEPTED_TOKEN; + encoded.write(recipient, recipientIndex, "hex"); + encoded.write(refundRecipient, recipientIndex + 32, "hex"); + return encoded; +} + +export interface Allocation { + allocation: BigNumber; // uint256 + excessContribution: BigNumber; // uint256 +} + +export function encodeAllocations(allocations: Allocation[]): Buffer { + const n = allocations.length; + const encoded = Buffer.alloc(NUM_BYTES_ALLOCATION * n); + for (let i = 0; i < n; ++i) { + const item = allocations[i]; + const start = i * NUM_BYTES_ALLOCATION; + encoded.writeUint8(i, start); + encoded.write(toBigNumberHex(item.allocation, 32), start + 1, "hex"); + encoded.write(toBigNumberHex(item.excessContribution, 32), start + 33, "hex"); + } + return encoded; +} + +export function encodeSaleSealed( + saleId: number, + allocations: Allocation[] // 65 * n_allocations +): Buffer { + const headerLen = 33; + const numAllocations = allocations.length; + const encoded = Buffer.alloc(headerLen + numAllocations * NUM_BYTES_ALLOCATION); + + encoded.writeUInt8(3, 0); // saleSealed payload = 3 + encoded.write(toBigNumberHex(saleId, 32), 1, "hex"); + encoded.write(encodeAllocations(allocations).toString("hex"), headerLen, "hex"); + + return encoded; +} + +export function encodeSaleAborted(saleId: number): Buffer { + const encoded = Buffer.alloc(33); + encoded.writeUInt8(4, 0); // saleSealed payload = 4 + encoded.write(toBigNumberHex(saleId, 32), 1, "hex"); + return encoded; +} + +function toBigNumberHex(value: BigNumberish, numBytes: number): string { + return BigNumber.from(value) + .toHexString() + .substring(2) + .padStart(numBytes * 2, "0"); +} + +// misc +export async function getBlockTime(terra: LCDClient): Promise { + const info = await terra.tendermint.blockInfo(); + const time = new Date(info.block.header.time); + return Math.floor(time.getTime() / 1000); +} + +export function getErrorMessage(error: any): string { + return error.response.data.message; +} + +// contract queries +export async function getBalance(terra: LCDClient, asset: string, account: string): Promise { + if (asset.startsWith("u")) { + const [balance] = await terra.bank.balance(account); + const coin = balance.get(asset); + if (coin !== undefined) { + return new Int(coin.amount); + } + return new Int(0); + } + + const msg: any = { + balance: { + address: account, + }, + }; + const result = await queryContract(terra, asset, msg); + return new Int(result.balance); +} + +export async function getBuyerStatus( + terra: LCDClient, + contributor: string, + saleId: Buffer, + tokenIndex: number, + buyer: string +): Promise { + const msg: any = { + buyer_status: { + sale_id: saleId.toString("base64"), + token_index: tokenIndex, + buyer, + }, + }; + const result = await queryContract(terra, contributor, msg); + + // verify header + for (let i = 0; i < 32; ++i) { + if (result.id[i] != saleId[i]) { + throw Error("id != expected"); + } + } + if (result.token_index != tokenIndex) { + throw Error("token_index != expected"); + } + if (result.buyer != buyer) { + throw Error("buyer != expected"); + } + return result.status; +} + +export async function getTotalContribution( + terra: LCDClient, + contributor: string, + saleId: Buffer, + tokenIndex: number +): Promise { + const msg: any = { + total_contribution: { + sale_id: saleId.toString("base64"), + token_index: tokenIndex, + }, + }; + const result = await queryContract(terra, contributor, msg); + + // verify header + for (let i = 0; i < 32; ++i) { + if (result.id[i] != saleId[i]) { + throw Error("id != expected"); + } + } + if (result.token_index != tokenIndex) { + throw Error("token_index != expected"); + } + return new Int(result.amount); +}