diff --git a/eth-sender/source/main.cpp b/eth-sender/source/main.cpp index 2ffd9a24a..a98a31a1e 100644 --- a/eth-sender/source/main.cpp +++ b/eth-sender/source/main.cpp @@ -30,8 +30,8 @@ #include "contract.hpp" #include "currency.hpp" #include "decimal.hpp" -#include "executor.hpp" #include "float.hpp" +#include "gnosis.hpp" #include "load.hpp" #include "local.hpp" #include "nested.hpp" @@ -48,14 +48,18 @@ namespace orc { // NOLINTBEGIN(cppcoreguidelines-avoid-non-const-global-variables) S base_; + +// XXX: sometimes used for flags_.bid_ +Flags flags_; + +// XXX: still used by Option_
::_ S chain_; S executor_; + std::string currency_; -uint256_t multiple_ = 1; std::optional nonce_; std::optional gas_; std::optional height_; -Locator rpc_{{"http", "127.0.0.1", "8545"}, "/"}; // NOLINTEND(cppcoreguidelines-avoid-non-const-global-variables) class Args : @@ -87,18 +91,18 @@ class Args : }; template -struct Option; +struct Option_; template -struct Option> { +struct Option_> { static std::optional _(std::string_view arg) { if (arg.empty()) return std::nullopt; - return Option::_(arg); + return Option_::_(arg); } }; template <> -struct Option { +struct Option_ { static bool _(std::string_view arg) { if (false); else if (arg == "true") @@ -109,55 +113,55 @@ static bool _(std::string_view arg) { } }; template <> -struct Option { +struct Option_ { static std::string _(std::string_view arg) { return std::string(arg); } }; template <> -struct Option { +struct Option_ { static Bytes32 _(std::string_view arg) { return Bless(arg); } }; template <> -struct Option { +struct Option_ { static Key _(std::string_view arg) { return ToKey(Bless(arg)); } }; template <> -struct Option { +struct Option_ { static Signature _(std::string_view arg) { return Brick<65>(Bless(arg)); } }; template <> -struct Option { +struct Option_ { static Decimal _(std::string_view arg) { return Decimal(arg); } }; template <> -struct Option { +struct Option_ { static uint64_t _(std::string_view arg) { return To(arg); } }; template <> -struct Option { +struct Option_ { static uint64_t _(std::string_view arg) { return To(arg); } }; template <> -struct Option { +struct Option_ { static int _(std::string_view arg) { return To(arg); } }; template <> -struct Option { +struct Option_ { static uint256_t _(std::string_view arg) { if (arg == "-1") return ~uint256_t(0); @@ -179,31 +183,32 @@ static uint256_t _(std::string_view arg) { } }; template <> -struct Option { +struct Option_ { static uint128_t _(std::string_view arg) { - return uint128_t(Option::_(arg)); + return uint128_t(Option_::_(arg)); } }; // XXX: this is incorrect because boost doesn't understand 2's compliment template <> -struct Option { +struct Option_ { static checked_int256_t _(std::string_view arg) { orc_assert(!arg.empty()); if (arg[0] != '-') - return Option::_(arg); - const auto value(Option::_(arg.substr(1))); + return Option_::_(arg); + const auto value(Option_::_(arg.substr(1))); return -checked_int256_t(value); } }; static const Address TransferV("0x2c1820DBc112149b30b8616Bf73D552BEa4C9F1F"); template <> -struct Option
{ +struct Option_
{ static Address _(std::string_view arg) { if (false); else if (arg == "0") { return "0x0000000000000000000000000000000000000000"; } else if (arg == "this") { + orc_assert_(executor_, "this requires executor address"); return executor_->operator Address(); } else if (arg == "factory@100") { @@ -217,7 +222,7 @@ static Address _(std::string_view arg) { return Locator_; } else if (arg == "lottery0") { - orc_assert_(*chain_ == 1, "lottery0 is not on chain " << chain_); + orc_assert_(!chain_ || *chain_ == 1, "lottery0 is not on chain " << chain_); return Lottery0_; } else if (arg == "lottery1") { return Lottery1_; } @@ -231,49 +236,49 @@ static Address _(std::string_view arg) { return TransferV; } else if (arg == "OTT") { - orc_assert_(*chain_ == 1, "OTT is not on chain " << chain_); + orc_assert_(!chain_ || *chain_ == 1, "OTT is not on chain " << chain_); return "0xff9978B7b309021D39a76f52Be377F2B95D72394"; } else if (arg == "OXT") { - orc_assert_(*chain_ == 1, "OXT is not on chain " << chain_); + orc_assert_(!chain_ || *chain_ == 1, "OXT is not on chain " << chain_); return "0x4575f41308EC1483f3d399aa9a2826d74Da13Deb"; } else if (arg == "DAI") { - orc_assert_(*chain_ == 1, "DAI is not on chain " << chain_); + orc_assert_(!chain_ || *chain_ == 1, "DAI is not on chain " << chain_); return "0x6B175474E89094C44Da98b954EedeAC495271d0F"; } else if (arg == "GUSD") { - orc_assert_(*chain_ == 1, "GUSD is not on chain " << chain_); + orc_assert_(!chain_ || *chain_ == 1, "GUSD is not on chain " << chain_); return "0x056Fd409E1d7A124BD7017459dFEa2F387b6d5Cd"; } else if (arg == "USDC") { - orc_assert_(*chain_ == 1, "USDC is not on chain " << chain_); + orc_assert_(!chain_ || *chain_ == 1, "USDC is not on chain " << chain_); return "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48"; } else if (arg == "WAVAX") { - orc_assert_(*chain_ == 43114, "WAVAX is not on chain " << chain_); + orc_assert_(!chain_ || *chain_ == 43114, "WAVAX is not on chain " << chain_); return "0xB31f66AA3C1e785363F0875A1B74E27b85FD66c7"; } else if (arg == "DAI-PSM-GUSD") { - orc_assert_(*chain_ == 1, "DAI is not on chain " << chain_); + orc_assert_(!chain_ || *chain_ == 1, "DAI is not on chain " << chain_); return "0x204659B2Fd2aD5723975c362Ce2230Fba11d3900"; } else if (arg == "DAI-PSM-USDC") { - orc_assert_(*chain_ == 1, "DAI is not on chain " << chain_); + orc_assert_(!chain_ || *chain_ == 1, "DAI is not on chain " << chain_); return "0x89B78CfA322F6C5dE0aBcEecab66Aee45393cC5A"; } else if (arg == "DAI-PSM-USDP") { - orc_assert_(*chain_ == 1, "DAI is not on chain " << chain_); + orc_assert_(!chain_ || *chain_ == 1, "DAI is not on chain " << chain_); return "0x961Ae24a1Ceba861D1FDf723794f6024Dc5485Cf"; } else return arg; } }; template <> -struct Option> { +struct Option_> { static std::optional
_(std::string_view arg) { if (arg == "null") return std::nullopt; - return Option
::_(arg); + return Option_
::_(arg); } }; template <> -struct Option { +struct Option_ { static Locator _(std::string_view arg) { if (false); else if (arg == "cloudflare") @@ -284,59 +289,32 @@ static Locator _(std::string_view arg) { } }; template <> -struct Option { +struct Option_ { static Any _(const std::string &arg) { return Parse(arg); } }; template <> -struct Option> { -static cppcoro::shared_task> _(std::string arg) { - if (boost::algorithm::starts_with(arg, "@")) { - const auto json(Parse(Load(arg.substr(1)))); - std::cout << json << std::endl; - orc_insist(false); - } else if (boost::algorithm::starts_with(arg, "m/")) { - std::vector indices; - arg = arg.substr(2); - for (const auto &span : Split(arg, {'/'})) { - std::string index(span); - orc_assert(!index.empty()); - bool flag; - if (index[index.size() - 1] != '\'') - flag = false; - else { - flag = true; - index = index.substr(0, index.size() - 1); - } - indices.push_back(To(index) | (flag ? 1 << 31 : 0)); - } - auto session(co_await TrezorSession::New(base_)); - auto executor(co_await TrezorExecutor::New(std::move(session), indices)); - co_return std::move(executor); - } else if (arg.size() == 64) - co_return Make(Bless(arg)); - else if (arg.size() == 42) - co_return Make(arg); - else orc_assert(false); -} }; - -template <> -struct Option { +struct Option_ { static Bytes _(std::string arg) { if (!arg.empty() && arg[0] == '@') arg = Load(arg.substr(1)); return Bless(arg); } }; +template +auto Option(Arg_ &&arg) { orc_block({ + return Option_::_(std::forward(arg)); +}, "parsing " << arg << " as " << typeid(Type_).name()); } + template std::tuple Options(Args &args, std::index_sequence) { - return std::tuple(Option::_(args[Indices_])...); + // NOLINTNEXTLINE(clang-analyzer-core.StackAddressEscape) + return std::tuple(Option(args[Indices_])...); } template auto Options(Args &args) { - // NOLINTNEXTLINE(clang-analyzer-core.StackAddressEscape) orc_assert(args.size() == sizeof...(Types_)); return Options(args, std::index_sequence_for()); } @@ -344,216 +322,38 @@ auto Options(Args &args) { task ScanState(const S &chain, uint64_t height); task ScanStorage(const S &chain, uint64_t height, const Address &address); -task Main(int argc, const char *const argv[]) { try { - Args args(argc - 1, argv + 1); - - #define ORC_PARAM(name, prefix, suffix) \ - else if (arg == "--" #name) { \ - static bool seen; \ - orc_assert(!seen); \ - seen = true; \ - prefix name##suffix = Option::_(args()); \ - } - - std::string executor; - Flags flags; - - const auto command([&]() { for (;;) { - auto arg(args()); - orc_assert(!arg.empty()); - if (arg[0] != '-') - return arg; - if (false); - ORC_PARAM(bid,flags.,_) - ORC_PARAM(height,,_) - ORC_PARAM(currency,,_) - ORC_PARAM(executor,,) - ORC_PARAM(gas,,_) - ORC_PARAM(nonce,,_) - ORC_PARAM(rpc,,_) - ORC_PARAM(verbose,flags.,_) - } }()); - - base_ = Break(); - chain_ = co_await Chain::New(Endpoint{rpc_, base_}, flags); - - if (executor.empty()) - executor_ = Make(); - else - executor_ = co_await Option::_(std::move(executor)); - - const auto block([&]() -> cppcoro::shared_task { - const auto height(height_ ? *height_ : co_await chain_->Height()); - const auto block(co_await chain_->Header(height)); - co_return block; - }); +task GetBlock(const S &chain) { + co_return co_await chain->Header(*height_); +} +task Command(const std::string &command, Args &args) { if (false) { - } else if (command == "account") { - const auto [address] = Options
(args); - const auto [account] = co_await chain_->Get(co_await block(), address, nullptr); - std::cout << account.balance_ << std::endl; - - } else if (command == "accounts") { - for (const auto &account : co_await (*chain_)("personal_listAccounts", {})) - std::cout << Address(account.asString()) << std::endl; - } else if (command == "address") { const auto [key] = Options(args); std::cout << Address(key) << std::endl; - } else if (command == "allowance") { - const auto [token, address, recipient] = Options(args); - static Selector allowance("allowance"); - std::cout << co_await allowance.Call(*chain_, "latest", token, 90000, address, recipient) << std::endl; - - } else if (command == "approve") { - const auto [token, recipient, amount] = Options(args); - static Selector approve("approve"); - std::cout << (co_await executor_->Send(*chain_, {.nonce = nonce_}, token, 0, approve(recipient, amount))).hex() << std::endl; - } else if (command == "avax") { // https://docs.avax.network/build/references/cryptographic-primitives const auto [key] = Options(args); std::cout << ToSegwit("avax", std::nullopt, HashR(Hash2(ToCompressed(key)))) << std::endl; - } else if (command == "balance") { - const auto [token, address] = Options(args); - static Selector balanceOf("balanceOf"); - std::cout << co_await balanceOf.Call(*chain_, "latest", token, 90000, address) << std::endl; - - } else if (command == "bid") { - Options<>(args); - std::cout << (co_await chain_->Bid()) << std::endl; - } else if (command == "binance") { const auto [pair] = Options(args); std::cout << co_await Binance(*base_, pair, 1) << std::endl; - } else if (command == "block") { - const auto [height] = Options(args); - std::cout << co_await (*chain_)("eth_getBlockByNumber", {height, true}) << std::endl; - - } else if (command == "block-rlp") { - const auto [height] = Options(args); - std::cout << Str(co_await chain_->Call("debug_getBlockRlp", {unsigned(height)})) << std::endl; - - } else if (command == "bsc:transfer") { - const auto [segwit, amount] = Options(args); - const auto recipient(FromSegwit(segwit)); - orc_assert(recipient.first == "bnb"); - const Address token("0x0000000000000000000000000000000000000000"); - const Address hub("0x0000000000000000000000000000000000001004"); - // https://raw.githubusercontent.com/binance-chain/bsc-genesis-contract/master/abi/tokenhub.abi - static Selector relayFee("relayFee"); - static Selector transferOut("transferOut"); - // XXX: gas is manually specified as eth_estimateGas failed to give this enough gas?! *sigh* :/ - std::cout << (co_await executor_->Send(*chain_, {.gas = 90000}, hub, amount + co_await relayFee.Call(*chain_, "latest", hub, 90000), transferOut(token, recipient.second.num(), amount, Timestamp() + 1000))).hex() << std::endl; - } else if (command == "cb58") { auto [data] = Options(args); std::cout << ToBase58(Tie(data, Hash2(data).Clip<28, 4>())) << std::endl; - } else if (command == "chain") { - Options<>(args); - std::cout << chain_->operator const uint256_t &() << std::endl; - - } else if (command == "chainlink") { - const auto [address] = Options
(args); - static Selector latestAnswer("latestAnswer"); - std::cout << std::dec << co_await latestAnswer.Call(*chain_, "latest", address, 90000) << std::endl; - - } else if (command == "code") { - const auto [address] = Options
(args); - std::cout << (co_await chain_->Code(co_await block(), address)).hex() << std::endl; - - } else if (command == "codehash") { - const auto [height, address] = Options(args); - Address contract; - std::cout << Str(co_await chain_->Call("eth_call", {Multi{ - {"from", "0x0000000000000000000000000000000000000000"}, - {"to", contract}, - {"gas", uint64_t(90000)}, - {"data", Number(address.num())}, - }, height, Multi{{contract.str(), Multi{{"code", "0x6000353f60005260206000f3"}}}}})) << std::endl; - } else if (command == "create2") { auto [factory, salt, code, data] = Options(args); std::cout << Address(HashK(Tie(uint8_t(0xff), factory, salt, HashK(Tie(code, data)))).skip<12>().num()) << std::endl; - } else if (command == "dai:buygem") { - auto [psm, buyer, amount] = Options(args); - static Selector buyGem("buyGem"); - std::cout << (co_await executor_->Send(*chain_, {.gas = gas_}, psm, 0, buyGem(buyer, amount))).hex() << std::endl; - - } else if (command == "dai:sellgem") { - auto [psm, seller, amount] = Options(args); - static Selector sellGem("sellGem"); - std::cout << (co_await executor_->Send(*chain_, {.gas = gas_}, psm, 0, sellGem(seller, amount))).hex() << std::endl; - - } else if (command == "debug") { - const auto [block] = Options(args); - const auto trace((co_await chain_->Call("debug_traceBlockByHash", {block, Multi{{"enableMemory", true}}})).as_array()); - std::cout << Unparse(trace) << std::endl; - - } else if (command == "deploy") { - auto [factory, amount, code, data] = Options, uint256_t, Bytes, Bytes>(args); - std::cout << (co_await executor_->Send(*chain_, {.gas = gas_}, factory, amount, Tie(code, data))).hex() << std::endl; - } else if (command == "derive") { const auto [secret] = Options(args); std::cout << ToUncompressed(Derive(secret)).hex() << std::endl; - } else if (command == "eip1820") { - Options<>(args); - const auto bid(flags.bid_ ? *flags.bid_ : uint256_t(100 * Ten9)); - static const uint256_t rs("0x1820182018201820182018201820182018201820182018201820182018201820"); - Record record(0, bid, 800000, std::nullopt, 0, Bless("608060405234801561001057600080fd5b506109c5806100206000396000f3fe608060405234801561001057600080fd5b50600436106100a5576000357c010000000000000000000000000000000000000000000000000000000090048063a41e7d5111610078578063a41e7d51146101d4578063aabbb8ca1461020a578063b705676514610236578063f712f3e814610280576100a5565b806329965a1d146100aa5780633d584063146100e25780635df8122f1461012457806365ba36c114610152575b600080fd5b6100e0600480360360608110156100c057600080fd5b50600160a060020a038135811691602081013591604090910135166102b6565b005b610108600480360360208110156100f857600080fd5b5035600160a060020a0316610570565b60408051600160a060020a039092168252519081900360200190f35b6100e06004803603604081101561013a57600080fd5b50600160a060020a03813581169160200135166105bc565b6101c26004803603602081101561016857600080fd5b81019060208101813564010000000081111561018357600080fd5b82018360208201111561019557600080fd5b803590602001918460018302840111640100000000831117156101b757600080fd5b5090925090506106b3565b60408051918252519081900360200190f35b6100e0600480360360408110156101ea57600080fd5b508035600160a060020a03169060200135600160e060020a0319166106ee565b6101086004803603604081101561022057600080fd5b50600160a060020a038135169060200135610778565b61026c6004803603604081101561024c57600080fd5b508035600160a060020a03169060200135600160e060020a0319166107ef565b604080519115158252519081900360200190f35b61026c6004803603604081101561029657600080fd5b508035600160a060020a03169060200135600160e060020a0319166108aa565b6000600160a060020a038416156102cd57836102cf565b335b9050336102db82610570565b600160a060020a031614610339576040805160e560020a62461bcd02815260206004820152600f60248201527f4e6f7420746865206d616e616765720000000000000000000000000000000000604482015290519081900360640190fd5b6103428361092a565b15610397576040805160e560020a62461bcd02815260206004820152601a60248201527f4d757374206e6f7420626520616e204552433136352068617368000000000000604482015290519081900360640190fd5b600160a060020a038216158015906103b85750600160a060020a0382163314155b156104ff5760405160200180807f455243313832305f4143434550545f4d4147494300000000000000000000000081525060140190506040516020818303038152906040528051906020012082600160a060020a031663249cb3fa85846040518363ffffffff167c01000000000000000000000000000000000000000000000000000000000281526004018083815260200182600160a060020a0316600160a060020a031681526020019250505060206040518083038186803b15801561047e57600080fd5b505afa158015610492573d6000803e3d6000fd5b505050506040513d60208110156104a857600080fd5b5051146104ff576040805160e560020a62461bcd02815260206004820181905260248201527f446f6573206e6f7420696d706c656d656e742074686520696e74657266616365604482015290519081900360640190fd5b600160a060020a03818116600081815260208181526040808320888452909152808220805473ffffffffffffffffffffffffffffffffffffffff19169487169485179055518692917f93baa6efbd2244243bfee6ce4cfdd1d04fc4c0e9a786abd3a41313bd352db15391a450505050565b600160a060020a03818116600090815260016020526040812054909116151561059a5750806105b7565b50600160a060020a03808216600090815260016020526040902054165b919050565b336105c683610570565b600160a060020a031614610624576040805160e560020a62461bcd02815260206004820152600f60248201527f4e6f7420746865206d616e616765720000000000000000000000000000000000604482015290519081900360640190fd5b81600160a060020a031681600160a060020a0316146106435780610646565b60005b600160a060020a03838116600081815260016020526040808220805473ffffffffffffffffffffffffffffffffffffffff19169585169590951790945592519184169290917f605c2dbf762e5f7d60a546d42e7205dcb1b011ebc62a61736a57c9089d3a43509190a35050565b600082826040516020018083838082843780830192505050925050506040516020818303038152906040528051906020012090505b92915050565b6106f882826107ef565b610703576000610705565b815b600160a060020a03928316600081815260208181526040808320600160e060020a031996909616808452958252808320805473ffffffffffffffffffffffffffffffffffffffff19169590971694909417909555908152600284528181209281529190925220805460ff19166001179055565b600080600160a060020a038416156107905783610792565b335b905061079d8361092a565b156107c357826107ad82826108aa565b6107b85760006107ba565b815b925050506106e8565b600160a060020a0390811660009081526020818152604080832086845290915290205416905092915050565b6000808061081d857f01ffc9a70000000000000000000000000000000000000000000000000000000061094c565b909250905081158061082d575080155b1561083d576000925050506106e8565b61084f85600160e060020a031961094c565b909250905081158061086057508015155b15610870576000925050506106e8565b61087a858561094c565b909250905060018214801561088f5750806001145b1561089f576001925050506106e8565b506000949350505050565b600160a060020a0382166000908152600260209081526040808320600160e060020a03198516845290915281205460ff1615156108f2576108eb83836107ef565b90506106e8565b50600160a060020a03808316600081815260208181526040808320600160e060020a0319871684529091529020549091161492915050565b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff161590565b6040517f01ffc9a7000000000000000000000000000000000000000000000000000000008082526004820183905260009182919060208160248189617530fa90519096909550935050505056fea165627a7a72305820377f4a2d4301ede9949f163f319021a6e9c687c292a5e2b2c4734c126b524e6c0029"), *chain_, 27u, rs, rs); - const auto [account] = co_await chain_->Get(co_await block(), record.from_, nullptr); - if (account.nonce_ != 0) - std::cout << record.hash_ << std::endl; - else { - orc_assert_(account.balance_ >= bid * record.gas_, record.from_ << " <= " << bid * record.gas_); - std::cout << (co_await chain_->Send("eth_sendRawTransaction", {Subset(Implode({record.nonce_, record.bid_, record.gas_, record.target_, record.amount_, record.data_, 27u, rs, rs}))})).hex() << std::endl; - } - - } else if (command == "eip2470") { - Options<>(args); - const auto bid(flags.bid_ ? *flags.bid_ : uint256_t(100 * Ten9)); - Record record(0, bid, 247000, std::nullopt, 0, Bless("608060405234801561001057600080fd5b50610134806100206000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c80634af63f0214602d575b600080fd5b60cf60048036036040811015604157600080fd5b810190602081018135640100000000811115605b57600080fd5b820183602082011115606c57600080fd5b80359060200191846001830284011164010000000083111715608d57600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929550509135925060eb915050565b604080516001600160a01b039092168252519081900360200190f35b6000818351602085016000f5939250505056fea26469706673582212206b44f8a82cb6b156bfcc3dc6aadd6df4eefd204bc928a4397fd15dacf6d5320564736f6c63430006020033"), *chain_, 27u, 0x247000u, 0x2470u); - const auto [account] = co_await chain_->Get(co_await block(), record.from_, nullptr); - if (account.nonce_ != 0) - std::cout << record.hash_ << std::endl; - else { - orc_assert_(account.balance_ >= bid * record.gas_, record.from_ << " <= " << bid * record.gas_); - std::cout << (co_await chain_->Send("eth_sendRawTransaction", {Subset(Implode({record.nonce_, record.bid_, record.gas_, record.target_, record.amount_, record.data_, 27u, 0x247000u, 0x2470u}))})).hex() << std::endl; - } - - // https://github.com/Zoltu/deterministic-deployment-proxy - } else if (command == "factory") { - Options<>(args); - const auto bid(flags.bid_ ? *flags.bid_ : uint256_t(100 * Ten9)); - static const uint256_t rs("0x2222222222222222222222222222222222222222222222222222222222222222"); - Record record(0, bid, 100000, std::nullopt, 0, Bless("601f80600e600039806000f350fe60003681823780368234f58015156014578182fd5b80825250506014600cf3"), *chain_, 27u, rs, rs); - const auto [account] = co_await chain_->Get(co_await block(), record.from_, nullptr); - if (account.nonce_ != 0) - std::cout << record.hash_ << std::endl; - else { - orc_assert_(account.balance_ >= bid * record.gas_, record.from_ << " <= " << bid * record.gas_); - std::cout << (co_await chain_->Send("eth_sendRawTransaction", {Subset(Implode({record.nonce_, record.bid_, record.gas_, record.target_, record.amount_, record.data_, 27u, rs, rs}))})).hex() << std::endl; - } - - } else if (command == "federation") { - static Selector> getFederationAddress("getFederationAddress"); - const auto [federation] = co_await getFederationAddress.Call(*chain_, "latest", "0x0000000000000000000000000000000001000006", 90000); - std::cout << federation << std::endl; - - } else if (command == "gas") { - const auto [address] = Options
(args); - const auto [account] = co_await chain_->Get(co_await block(), address, nullptr); - std::cout << account.balance_ / co_await chain_->Bid() << std::endl; - } else if (command == "generate") { Options<>(args); const auto secret(Random<32>()); @@ -563,10 +363,6 @@ task Main(int argc, const char *const argv[]) { try { auto [data] = Options(args); std::cout << HashK(data).hex() << std::endl; - } else if (command == "height") { - Options<>(args); - std::cout << co_await chain_->Height() << std::endl; - } else if (command == "hex") { Options<>(args); std::cout << "0x"; @@ -583,65 +379,10 @@ task Main(int argc, const char *const argv[]) { try { } std::cout << std::endl; - } else if (command == "lottery0:look") { - const auto [lottery, funder, signer] = Options(args); - static Selector, Address, Address> look("look"); - const auto [amount, escrow, unlock, verify, codehash, shared] = co_await look.Call(*chain_, "latest", lottery, 90000, funder, signer); - std::cout << amount << " " << escrow << " " << unlock << std::endl; - - } else if (command == "lottery0:push") { - const auto [lottery, signer, balance, escrow] = Options(args); - static Selector push("push"); - std::cout << (co_await executor_->Send(*chain_, {.gas = 175000}, lottery, 0, push(signer, balance + escrow, escrow))).hex() << std::endl; - - } else if (command == "lottery1:edit") { - const auto [lottery, amount, signer, adjust, lock, retrieve] = Options(args); - static Selector edit("edit"); - std::cout << (co_await executor_->Send(*chain_, {}, lottery, amount, edit(signer, adjust, lock, retrieve))).hex() << std::endl; - - } else if (command == "lottery1:enrolled") { - const auto [lottery, funder, recipient] = Options(args); - static Selector enrolled("enrolled"); - std::cout << co_await enrolled.Call(*chain_, "latest", lottery, 90000, funder, recipient) << std::endl; - - } else if (command == "lottery1:mark") { - const auto [lottery, token, signer, marked] = Options(args); - static Selector mark("mark"); - std::cout << (co_await executor_->Send(*chain_, {}, lottery, 0, mark(token, signer, marked))).hex() << std::endl; - - } else if (command == "lottery1:read") { - const auto [lottery, token, funder, signer] = Options(args); - static Selector, Address, Address, Address> read("read"); - const auto [escrow_balance, unlock_warned] = co_await read.Call(*chain_, "latest", lottery, 90000, token, funder, signer); - std::cout << uint128_t(escrow_balance) << " " << (escrow_balance >> 128) << " " << uint128_t(unlock_warned) << " " << uint64_t(unlock_warned >> 128) << " " << (unlock_warned >> 192) << std::endl; - - } else if (command == "nonce") { - const auto [address] = Options
(args); - const auto [account] = co_await chain_->Get(co_await block(), address, nullptr); - std::cout << account.nonce_ << std::endl; - } else if (command == "number") { const auto [number] = Options(args); std::cout << "0x" << std::hex << number << std::endl; - } else if (command == "orchid:locate") { - const auto [stakee] = Options
(args); - static Selector, Address> look("look"); - const auto [set, url, tls, gpg] = co_await look.Call(*chain_, "latest", Locator_, 90000, stakee); - std::cout << url.str() << std::endl; - - } else if (command == "orchid:pulled") { - const auto [staker, index] = Options(args); - const auto pending(HashK(Tie(index, HashK(Tie(uint256_t(staker.num()), uint256_t(0x4u))))).num()); - const auto [contract, expire, stakee, amount] = co_await chain_->Get(co_await block(), Directory_, nullptr, pending + 0, pending + 1, pending + 2); - std::cout << expire << " " << Address(stakee) << " " << amount << std::endl; - - } else if (command == "orchid:staked") { - const auto [staker, stakee] = Options(args); - const auto stake(HashK(Tie(HashK(Tie(staker, stakee)), uint256_t(0x2u))).num()); - const auto [contract, amount, delay] = co_await chain_->Get(co_await block(), Directory_, nullptr, stake + 2, stake + 3); - std::cout << amount << " " << delay << std::endl; - } else if (command == "p2pkh") { // https://en.bitcoin.it/wiki/Technical_background_of_version_1_Bitcoin_addresses const auto [key] = Options(args); @@ -657,35 +398,10 @@ task Main(int argc, const char *const argv[]) { try { const auto [key] = Options(args); std::cout << ToSegwit("bc", 0, Hash2(Tie(uint8_t(0x21), ToCompressed(key), uint8_t(0xac)))) << std::endl; - } else if (command == "price") { - const auto [symbol] = Options(args); - const auto ethereum(Make(chain_)); - const auto currency(co_await Currency::New(5000, ethereum, base_, symbol)); - std::cout << currency.dollars_() << std::endl; - - } else if (command == "read") { - const auto [contract, slot] = Options(args); - const auto [account, value] = co_await chain_->Get(co_await block(), contract, nullptr, slot); - std::cout << "0x" << std::hex << value << std::endl; - - } else if (command == "receipt") { - const auto [transaction] = Options(args); - for (;;) { - const auto receipt(co_await (*chain_)("eth_getTransactionReceipt", {transaction})); - if (receipt.isNull()) - continue; - std::cout << receipt << std::endl; - break; - } - } else if (command == "recover") { const auto [signature, message] = Options(args); std::cout << ToUncompressed(Recover(HashK(message), signature)).hex() << std::endl; - } else if (command == "resolve") { - const auto [name] = Options(args); - std::cout << co_await Resolve(*chain_, (co_await block()).height_, name) << std::endl; - } else if (command == "rlp-decode") { const auto [data] = Options(args); Window window(data); @@ -708,164 +424,348 @@ task Main(int argc, const char *const argv[]) { try { std::cout << " " << window << std::endl; std::cout << std::endl; - } else if (command == "run") { - const auto [code, recipient, amount, data] = Options, uint256_t, Bytes>(args); - const auto contract(recipient ? *recipient : Address(Random<20>())); - std::cout << Str(co_await chain_->Call("eth_call", {Multi{ - {"from", executor_->operator Address()}, - {"to", contract}, - {"gas", gas_}, - {"gasPrice", flags.bid_}, - {"value", amount}, - {"data", data}, - }, (co_await block()).height_, Multi{ - {executor_->operator Address().str(), Multi{{"balance", amount}}}, - {contract.str(), Multi{{"code", code}}}, - }})) << std::endl; - } else if (command == "segwit") { const auto [prefix, version, key] = Options, Key>(args); std::cout << ToSegwit(prefix, version, HashR(Hash2(ToCompressed(key)))) << std::endl; - } else if (command == "seller:allow1") { - const auto [seller, token, allowance, sender] = Options(args); - static Selector> allow("allow"); - std::cout << (co_await executor_->Send(*chain_, {}, seller, 0, allow(token, allowance, {sender}))).hex() << std::endl; + } else if (command == "sign") { + const auto [secret, message] = Options(args); + std::cout << Sign(secret, HashK(message)).operator Brick<65>().hex() << std::endl; - } else if (command == "seller:allowed") { - const auto [seller, token, sender] = Options(args); - static Selector allowed("allowed"); - std::cout << co_await allowed.Call(*chain_, "latest", seller, 90000, token, sender) << std::endl; + } else if (command == "timestamp") { + Options<>(args); + std::cout << Timestamp() << std::endl; - } else if (command == "seller:enroll1") { - const auto [seller, cancel, recipient] = Options(args); - static Selector> enroll("enroll"); - std::cout << (co_await executor_->Send(*chain_, {}, seller, 0, enroll(cancel, {recipient}))).hex() << std::endl; + } else if (command == "wif") { + // https://en.bitcoin.it/wiki/Wallet_import_format + // prefix with 0x80 for mainnet and 0xEF for testnet + // suffix with 0x01 if this will be a compressed key + const auto [data] = Options(args); + std::cout << ToBase58Check(data) << std::endl; - } else if (command == "seller:giftv") { - orc_assert(nonce_); - const auto [seller] = Options
(args); + } else orc_assert_(false, "unknown command " << command); +} - typedef std::tuple Gift; - std::vector gifts; - uint256_t total(0); +task Command(const std::string &command, Args &args, const S &chain) { + if (false) { - const auto csv(Load(std::to_string(uint64_t(*nonce_)) + ".csv")); - for (auto line : Split(csv, {'\n'})) { - if (line.empty() || line[0] == '#') - continue; - if (line[line.size() - 1] == '\r') { - line -= 1; - if (line.empty()) - continue; - } + } else if (command == "account") { + const auto [address] = Options
(args); + const auto [account] = co_await chain->Get(co_await GetBlock(chain), address, nullptr); + std::cout << account.balance_ << std::endl; - const auto comma0(Find(line, {','})); - orc_assert(comma0); - auto [recipient, rest] = Split(line, *comma0); + } else if (command == "accounts") { + for (const auto &account : co_await (*chain)("personal_listAccounts", {})) + std::cout << Address(account.asString()) << std::endl; - const auto comma1(Find(rest, {','})); - orc_assert(comma1); - auto [amount$, escrow$] = Split(rest, *comma1); + } else if (command == "bid") { + Options<>(args); + std::cout << (co_await chain->Bid()) << std::endl; - const uint256_t amount{std::string(amount$)}; - const uint256_t escrow{std::string(escrow$)}; + } else if (command == "block") { + Options<>(args); + std::cout << co_await (*chain)("eth_getBlockByNumber", {*height_, true}) << std::endl; - const auto combined(amount + escrow); - orc_assert(combined >= escrow); + } else if (command == "block-rlp") { + Options<>(args); + std::cout << Str(co_await chain->Call("debug_getBlockRlp", {unsigned(*height_)})) << std::endl; - const auto &gift(gifts.emplace_back(std::string(recipient), combined, escrow)); - std::cout << "gift " << seller << " " << std::get<0>(gift) << " " << std::get<1>(gift) << " " << std::get<2>(gift) << std::endl; - total += std::get<1>(gift); + } else if (command == "chain") { + Options<>(args); + std::cout << chain->operator const uint256_t &() << std::endl; + + } else if (command == "chainlink") { + const auto [address] = Options
(args); + static Selector latestAnswer("latestAnswer"); + std::cout << std::dec << co_await latestAnswer.Call(*chain, "latest", address, 90000) << std::endl; + + } else if (command == "code") { + const auto [address] = Options
(args); + std::cout << (co_await chain->Code(co_await GetBlock(chain), address)).hex() << std::endl; + + } else if (command == "codehash") { + const auto [address] = Options
(args); + Address contract; + std::cout << Str(co_await chain->Call("eth_call", {Multi{ + {"from", "0x0000000000000000000000000000000000000000"}, + {"to", contract}, + {"gas", uint64_t(90000)}, + {"data", Number(address.num())}, + }, *height_, Multi{{contract.str(), Multi{{"code", "0x6000353f60005260206000f3"}}}}})) << std::endl; + + } else if (command == "debug") { + const auto [block] = Options(args); + const auto trace((co_await chain->Call("debug_traceBlockByHash", {block, Multi{{"enableMemory", true}}})).as_array()); + std::cout << Unparse(trace) << std::endl; + + } else if (command == "deploy:eip1820") { + Options<>(args); + const auto bid(flags_.bid_ ? *flags_.bid_ : uint256_t(100 * Ten9)); + static const uint256_t rs("0x1820182018201820182018201820182018201820182018201820182018201820"); + Record record(0, bid, 800000, std::nullopt, 0, Bless("608060405234801561001057600080fd5b506109c5806100206000396000f3fe608060405234801561001057600080fd5b50600436106100a5576000357c010000000000000000000000000000000000000000000000000000000090048063a41e7d5111610078578063a41e7d51146101d4578063aabbb8ca1461020a578063b705676514610236578063f712f3e814610280576100a5565b806329965a1d146100aa5780633d584063146100e25780635df8122f1461012457806365ba36c114610152575b600080fd5b6100e0600480360360608110156100c057600080fd5b50600160a060020a038135811691602081013591604090910135166102b6565b005b610108600480360360208110156100f857600080fd5b5035600160a060020a0316610570565b60408051600160a060020a039092168252519081900360200190f35b6100e06004803603604081101561013a57600080fd5b50600160a060020a03813581169160200135166105bc565b6101c26004803603602081101561016857600080fd5b81019060208101813564010000000081111561018357600080fd5b82018360208201111561019557600080fd5b803590602001918460018302840111640100000000831117156101b757600080fd5b5090925090506106b3565b60408051918252519081900360200190f35b6100e0600480360360408110156101ea57600080fd5b508035600160a060020a03169060200135600160e060020a0319166106ee565b6101086004803603604081101561022057600080fd5b50600160a060020a038135169060200135610778565b61026c6004803603604081101561024c57600080fd5b508035600160a060020a03169060200135600160e060020a0319166107ef565b604080519115158252519081900360200190f35b61026c6004803603604081101561029657600080fd5b508035600160a060020a03169060200135600160e060020a0319166108aa565b6000600160a060020a038416156102cd57836102cf565b335b9050336102db82610570565b600160a060020a031614610339576040805160e560020a62461bcd02815260206004820152600f60248201527f4e6f7420746865206d616e616765720000000000000000000000000000000000604482015290519081900360640190fd5b6103428361092a565b15610397576040805160e560020a62461bcd02815260206004820152601a60248201527f4d757374206e6f7420626520616e204552433136352068617368000000000000604482015290519081900360640190fd5b600160a060020a038216158015906103b85750600160a060020a0382163314155b156104ff5760405160200180807f455243313832305f4143434550545f4d4147494300000000000000000000000081525060140190506040516020818303038152906040528051906020012082600160a060020a031663249cb3fa85846040518363ffffffff167c01000000000000000000000000000000000000000000000000000000000281526004018083815260200182600160a060020a0316600160a060020a031681526020019250505060206040518083038186803b15801561047e57600080fd5b505afa158015610492573d6000803e3d6000fd5b505050506040513d60208110156104a857600080fd5b5051146104ff576040805160e560020a62461bcd02815260206004820181905260248201527f446f6573206e6f7420696d706c656d656e742074686520696e74657266616365604482015290519081900360640190fd5b600160a060020a03818116600081815260208181526040808320888452909152808220805473ffffffffffffffffffffffffffffffffffffffff19169487169485179055518692917f93baa6efbd2244243bfee6ce4cfdd1d04fc4c0e9a786abd3a41313bd352db15391a450505050565b600160a060020a03818116600090815260016020526040812054909116151561059a5750806105b7565b50600160a060020a03808216600090815260016020526040902054165b919050565b336105c683610570565b600160a060020a031614610624576040805160e560020a62461bcd02815260206004820152600f60248201527f4e6f7420746865206d616e616765720000000000000000000000000000000000604482015290519081900360640190fd5b81600160a060020a031681600160a060020a0316146106435780610646565b60005b600160a060020a03838116600081815260016020526040808220805473ffffffffffffffffffffffffffffffffffffffff19169585169590951790945592519184169290917f605c2dbf762e5f7d60a546d42e7205dcb1b011ebc62a61736a57c9089d3a43509190a35050565b600082826040516020018083838082843780830192505050925050506040516020818303038152906040528051906020012090505b92915050565b6106f882826107ef565b610703576000610705565b815b600160a060020a03928316600081815260208181526040808320600160e060020a031996909616808452958252808320805473ffffffffffffffffffffffffffffffffffffffff19169590971694909417909555908152600284528181209281529190925220805460ff19166001179055565b600080600160a060020a038416156107905783610792565b335b905061079d8361092a565b156107c357826107ad82826108aa565b6107b85760006107ba565b815b925050506106e8565b600160a060020a0390811660009081526020818152604080832086845290915290205416905092915050565b6000808061081d857f01ffc9a70000000000000000000000000000000000000000000000000000000061094c565b909250905081158061082d575080155b1561083d576000925050506106e8565b61084f85600160e060020a031961094c565b909250905081158061086057508015155b15610870576000925050506106e8565b61087a858561094c565b909250905060018214801561088f5750806001145b1561089f576001925050506106e8565b506000949350505050565b600160a060020a0382166000908152600260209081526040808320600160e060020a03198516845290915281205460ff1615156108f2576108eb83836107ef565b90506106e8565b50600160a060020a03808316600081815260208181526040808320600160e060020a0319871684529091529020549091161492915050565b7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff161590565b6040517f01ffc9a7000000000000000000000000000000000000000000000000000000008082526004820183905260009182919060208160248189617530fa90519096909550935050505056fea165627a7a72305820377f4a2d4301ede9949f163f319021a6e9c687c292a5e2b2c4734c126b524e6c0029"), *chain, 27u, rs, rs); + const auto [account] = co_await chain->Get(co_await GetBlock(chain), record.from_, nullptr); + if (account.nonce_ != 0) + std::cout << record.hash_ << std::endl; + else { + orc_assert_(account.balance_ >= bid * record.gas_, record.from_ << " <= " << bid * record.gas_); + std::cout << (co_await chain->Send("eth_sendRawTransaction", {Subset(Implode({record.nonce_, record.bid_, record.gas_, record.target_, record.amount_, record.data_, 27u, rs, rs}))})).hex() << std::endl; } - std::cout << "total = " << total << std::endl; + } else if (command == "deploy:eip2470") { + Options<>(args); + const auto bid(flags_.bid_ ? *flags_.bid_ : uint256_t(100 * Ten9)); + Record record(0, bid, 247000, std::nullopt, 0, Bless("608060405234801561001057600080fd5b50610134806100206000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c80634af63f0214602d575b600080fd5b60cf60048036036040811015604157600080fd5b810190602081018135640100000000811115605b57600080fd5b820183602082011115606c57600080fd5b80359060200191846001830284011164010000000083111715608d57600080fd5b91908080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250929550509135925060eb915050565b604080516001600160a01b039092168252519081900360200190f35b6000818351602085016000f5939250505056fea26469706673582212206b44f8a82cb6b156bfcc3dc6aadd6df4eefd204bc928a4397fd15dacf6d5320564736f6c63430006020033"), *chain, 27u, 0x247000u, 0x2470u); + const auto [account] = co_await chain->Get(co_await GetBlock(chain), record.from_, nullptr); + if (account.nonce_ != 0) + std::cout << record.hash_ << std::endl; + else { + orc_assert_(account.balance_ >= bid * record.gas_, record.from_ << " <= " << bid * record.gas_); + std::cout << (co_await chain->Send("eth_sendRawTransaction", {Subset(Implode({record.nonce_, record.bid_, record.gas_, record.target_, record.amount_, record.data_, 27u, 0x247000u, 0x2470u}))})).hex() << std::endl; + } - static Selector> giftv("giftv"); - std::cout << (co_await executor_->Send(*chain_, {.nonce = nonce_}, seller, total, giftv(gifts))).hex() << std::endl; + // https://github.com/Zoltu/deterministic-deployment-proxy + } else if (command == "deploy:factory") { + Options<>(args); + const auto bid(flags_.bid_ ? *flags_.bid_ : uint256_t(100 * Ten9)); + static const uint256_t rs("0x2222222222222222222222222222222222222222222222222222222222222222"); + Record record(0, bid, 100000, std::nullopt, 0, Bless("601f80600e600039806000f350fe60003681823780368234f58015156014578182fd5b80825250506014600cf3"), *chain, 27u, rs, rs); + const auto [account] = co_await chain->Get(co_await GetBlock(chain), record.from_, nullptr); + if (account.nonce_ != 0) + std::cout << record.hash_ << std::endl; + else { + orc_assert_(account.balance_ >= bid * record.gas_, record.from_ << " <= " << bid * record.gas_); + std::cout << (co_await chain->Send("eth_sendRawTransaction", {Subset(Implode({record.nonce_, record.bid_, record.gas_, record.target_, record.amount_, record.data_, 27u, rs, rs}))})).hex() << std::endl; + } - } else if (command == "seller:hand") { - const auto [seller, owner, manager] = Options(args); - static Selector hand("hand"); - std::cout << (co_await executor_->Send(*chain_, {}, seller, 0, hand(owner, manager))).hex() << std::endl; + } else if (command == "erc20:allowance") { + const auto [token, address, target] = Options(args); + static Selector allowance("allowance"); + std::cout << co_await allowance.Call(*chain, "latest", token, 90000, address, target) << std::endl; - } else if (command == "seller:move") { - const auto [url, tls, gpg] = Options(args); - static Selector move("move"); - std::cout << (co_await executor_->Send(*chain_, {.nonce = nonce_}, "0xEF7bc12e0F6B02fE2cb86Aa659FdC3EBB727E0eD", 0, move(url, tls, gpg))).hex() << std::endl; + } else if (command == "erc20:balance") { + const auto [token, address] = Options(args); + static Selector balanceOf("balanceOf"); + std::cout << co_await balanceOf.Call(*chain, "latest", token, 90000, address) << std::endl; + + } else if (command == "federation") { + static Selector> getFederationAddress("getFederationAddress"); + const auto [federation] = co_await getFederationAddress.Call(*chain, "latest", "0x0000000000000000000000000000000001000006", 90000); + std::cout << federation << std::endl; + + } else if (command == "gas") { + const auto [address] = Options
(args); + const auto [account] = co_await chain->Get(co_await GetBlock(chain), address, nullptr); + std::cout << account.balance_ / co_await chain->Bid() << std::endl; + + } else if (command == "height") { + Options<>(args); + std::cout << *height_ << std::endl; + + } else if (command == "lottery0:look") { + const auto [lottery, funder, signer] = Options(args); + static Selector, Address, Address> look("look"); + const auto [amount, escrow, unlock, verify, codehash, shared] = co_await look.Call(*chain, "latest", lottery, 90000, funder, signer); + std::cout << amount << " " << escrow << " " << unlock << std::endl; + + } else if (command == "lottery1:enrolled") { + const auto [lottery, funder, recipient] = Options(args); + static Selector enrolled("enrolled"); + std::cout << co_await enrolled.Call(*chain, "latest", lottery, 90000, funder, recipient) << std::endl; + + } else if (command == "lottery1:read") { + const auto [lottery, token, funder, signer] = Options(args); + static Selector, Address, Address, Address> read("read"); + const auto [escrow_balance, unlock_warned] = co_await read.Call(*chain, "latest", lottery, 90000, token, funder, signer); + std::cout << uint128_t(escrow_balance) << " " << (escrow_balance >> 128) << " " << uint128_t(unlock_warned) << " " << uint64_t(unlock_warned >> 128) << " " << (unlock_warned >> 192) << std::endl; + + } else if (command == "multisig:confirmations") { + const auto [address, index] = Options(args); + static Selector>, uint256_t> getConfirmations("getConfirmations"); + const auto [confirmations] = co_await getConfirmations.Call(*chain, "latest", address, 90000, index); + for (const auto &confirmation : confirmations) + std::cout << confirmation << std::endl; + + } else if (command == "multisig:nonce") { + const auto [address] = Options
(args); + const auto [account, count] = co_await chain->Get(co_await GetBlock(chain), address, nullptr, 0x5); + std::cout << count << std::endl; + + } else if (command == "multisig:owners") { + const auto [address] = Options
(args); + static Selector>> getOwners("getOwners"); + const auto [owners] = co_await getOwners.Call(*chain, *height_, address, 90000); + for (const auto &owner : owners) + std::cout << owner << std::endl; + + } else if (command == "multisig:transaction") { + const auto [address, index] = Options(args); + static Selector, uint256_t> transactions("transactions"); + const auto [target, value, data, executed] = co_await transactions.Call(*chain, "latest", address, 90000, index); + std::cout << executed << " " << target << " " << value << " " << data << std::endl; + + } else if (command == "nonce") { + const auto [address] = Options
(args); + const auto [account] = co_await chain->Get(co_await GetBlock(chain), address, nullptr); + std::cout << account.nonce_ << std::endl; + + } else if (command == "orchid:locate") { + const auto [stakee] = Options
(args); + static Selector, Address> look("look"); + const auto [set, url, tls, gpg] = co_await look.Call(*chain, "latest", Locator_, 90000, stakee); + std::cout << url.str() << std::endl; + + } else if (command == "orchid:pulled") { + const auto [staker, index] = Options(args); + const auto pending(HashK(Tie(index, HashK(Tie(uint256_t(staker.num()), uint256_t(0x4u))))).num()); + const auto [contract, expire, stakee, amount] = co_await chain->Get(co_await GetBlock(chain), Directory_, nullptr, pending + 0, pending + 1, pending + 2); + std::cout << expire << " " << Address(stakee) << " " << amount << std::endl; + + } else if (command == "orchid:staked") { + const auto [staker, stakee] = Options(args); + const auto stake(HashK(Tie(HashK(Tie(staker, stakee)), uint256_t(0x2u))).num()); + const auto [contract, amount, delay] = co_await chain->Get(co_await GetBlock(chain), Directory_, nullptr, stake + 2, stake + 3); + std::cout << amount << " " << delay << std::endl; + + } else if (command == "price") { + const auto [symbol] = Options(args); + const auto ethereum(Make(chain)); + const auto currency(co_await Currency::New(5000, ethereum, base_, symbol)); + std::cout << currency.dollars_() << std::endl; + + } else if (command == "read") { + const auto [contract, slot] = Options(args); + const auto [account, value] = co_await chain->Get(co_await GetBlock(chain), contract, nullptr, slot); + std::cout << "0x" << std::hex << value << std::endl; + + } else if (command == "receipt") { + const auto [transaction] = Options(args); + for (;;) { + const auto receipt(co_await (*chain)("eth_getTransactionReceipt", {transaction})); + if (receipt.isNull()) + continue; + std::cout << receipt << std::endl; + break; + } + + } else if (command == "resolve") { + const auto [name] = Options(args); + std::cout << co_await Resolve(*chain, *height_, name) << std::endl; + + } else if (command == "seller:allowed") { + const auto [seller, token, sender] = Options(args); + static Selector allowed("allowed"); + std::cout << co_await allowed.Call(*chain, "latest", seller, 90000, token, sender) << std::endl; } else if (command == "seller:read") { const auto [seller, token, signer] = Options(args); orc_assert(token == Address(0)); static Selector read("read"); - const auto packed(co_await read.Call(*chain_, "latest", seller, 90000, signer)); + const auto packed(co_await read.Call(*chain, "latest", seller, 90000, signer)); std::cout << std::dec << (packed >> 64) << " " << uint64_t(packed) << std::endl; - } else if (command == "send") { - const auto [recipient, amount, data] = Options(args); - std::cout << (co_await executor_->Send(*chain_, {.nonce = nonce_, .gas = gas_}, recipient, amount, data)).hex() << std::endl; - - } else if (command == "sign") { - const auto [secret, message] = Options(args); - std::cout << Sign(secret, HashK(message)).operator Brick<65>().hex() << std::endl; - - } else if (command == "singleton-100") { - auto [code, salt] = Options(args); - static Selector deploy("deploy"); - static Address factory("0xce0042B868300000d44A59004Da54A005ffdcf9f"); - std::cout << (co_await executor_->Send(*chain_, {.gas = 3000000}, factory, 0, deploy(code, salt))).hex() << std::endl; - - } else if (command == "singleton-500") { - auto [code, salt] = Options(args); - static Selector deploy("deploy"); - static Address factory("0xe14b5ae0d1e8a4e9039d40e5bf203fd21e2f6241"); - std::cout << (co_await executor_->Send(*chain_, {.gas = 3000000}, factory, 0, deploy(code, salt))).hex() << std::endl; - } else if (command == "slot") { - auto [height, address, slot] = Options(args); - std::cout << Str(co_await chain_->Call("eth_getStorageAt", {address, slot, height})) << std::endl; + auto [address, slot] = Options(args); + std::cout << Str(co_await chain->Call("eth_getStorageAt", {address, slot, *height_})) << std::endl; } else if (command == "slot-ex") { - auto [height, address, slot] = Options(args); - std::cout << Str(co_await chain_->Call("eth_call", {Multi{ + auto [address, slot] = Options(args); + std::cout << Str(co_await chain->Call("eth_call", {Multi{ {"from", "0x0000000000000000000000000000000000000000"}, {"to", address}, {"gas", uint64_t(90000)}, {"data", Number(slot)}, - }, height, Multi{{address.str(), Multi{{"code", "0x6000355460005260206000f3"}}}}})) << std::endl; + }, *height_, Multi{{address.str(), Multi{{"code", "0x6000355460005260206000f3"}}}}})) << std::endl; } else if (command == "state") { - const auto [height] = Options(args); - co_await ScanState(chain_, height); + Options<>(args); + co_await ScanState(chain, *height_); } else if (command == "storage") { - const auto [height, address] = Options(args); - co_await ScanStorage(chain_, height, address); + const auto [address] = Options
(args); + co_await ScanStorage(chain, *height_, address); } else if (command == "submit") { const auto [raw] = Options(args); - std::cout << (co_await chain_->Send("eth_sendRawTransaction", {raw})).hex() << std::endl; + std::cout << (co_await chain->Send("eth_sendRawTransaction", {raw})).hex() << std::endl; - } else if (command == "this") { - Options<>(args); - std::cout << executor_->operator Address() << std::endl; + } else if (command == "transaction") { + const auto [transaction] = Options(args); + std::cout << co_await (*chain)("eth_getTransactionByHash", {transaction}) << std::endl; - } else if (command == "timestamp") { + } else if (command == "uniswap2") { + const auto [pool] = Options
(args); + std::cout << co_await Uniswap2(*chain, pool, 1) << std::endl; + + } else if (command == "uniswap3") { + const auto [pool] = Options
(args); + std::cout << co_await Uniswap3(*chain, pool, 1) << std::endl; + + } else if (command == "value") { + const auto [address] = Options
(args); + const auto [account] = co_await chain->Get(co_await GetBlock(chain), address, nullptr); + std::cout << Float(account.balance_) * co_await Binance(*base_, currency_ + "USDT", Ten18) << std::endl; + + } else if (command == "verify") { Options<>(args); - std::cout << Timestamp() << std::endl; + auto height(*height_); + do { + co_await chain->Header(height); + if (height % 1000 == 0) + std::cerr << height << std::endl; + } while (height-- != 0); + + } else co_return co_await Command(command, args); +} + +task CommandExecutor(Args &args, const S &chain, const S &executor) { + const auto command(args()); + if (false) { + + } else if (command == "multisig") { + const auto address(Option
(args())); + executor_ = Make(address, std::move(executor_)); + co_return co_await CommandExecutor(args, chain_, executor_); - } else if (command == "transaction") { - const auto [transaction] = Options(args); - std::cout << co_await (*chain_)("eth_getTransactionByHash", {transaction}) << std::endl; - } else if (command == "transfer") { - const auto [token, recipient, amount, data] = Options(args); + } else if (command == "bsc:transfer") { + const auto [segwit, amount] = Options(args); + const auto recipient(FromSegwit(segwit)); + orc_assert(recipient.first == "bnb"); + const Address token("0x0000000000000000000000000000000000000000"); + const Address hub("0x0000000000000000000000000000000000001004"); + // https://raw.githubusercontent.com/binance-chain/bsc-genesis-contract/master/abi/tokenhub.abi + static Selector relayFee("relayFee"); + static Selector transferOut("transferOut"); + // XXX: gas is manually specified as eth_estimateGas failed to give this enough gas?! *sigh* :/ + std::cout << (co_await executor->Send(*chain, {.gas = 90000}, hub, amount + co_await relayFee.Call(*chain, "latest", hub, 90000), transferOut(token, recipient.second.num(), amount, Timestamp() + 1000))).hex() << std::endl; + + } else if (command == "dai:buygem") { + auto [psm, buyer, amount] = Options(args); + static Selector buyGem("buyGem"); + std::cout << (co_await executor->Send(*chain, {.gas = gas_}, psm, 0, buyGem(buyer, amount))).hex() << std::endl; + + } else if (command == "dai:sellgem") { + auto [psm, seller, amount] = Options(args); + static Selector sellGem("sellGem"); + std::cout << (co_await executor->Send(*chain, {.gas = gas_}, psm, 0, sellGem(seller, amount))).hex() << std::endl; + + } else if (command == "deploy") { + auto [factory, amount, code, data] = Options, uint256_t, Bytes, Bytes>(args); + std::cout << (co_await executor->Send(*chain, {.gas = gas_}, factory, amount, Tie(code, data))).hex() << std::endl; + + } else if (command == "erc20:approve") { + const auto [token, target, amount] = Options(args); + static Selector approve("approve"); + std::cout << (co_await executor->Send(*chain, {.nonce = nonce_}, token, 0, approve(target, amount))).hex() << std::endl; + + } else if (command == "erc20:transfer") { + const auto [token, target, amount, data] = Options(args); static Selector transfer("transfer"); static Selector transferAndCall("transferAndCall"); - std::cout << (co_await executor_->Send(*chain_, {}, token, 0, data.size() == 0 ? - transfer(recipient, amount) : transferAndCall(recipient, amount, data))).hex() << std::endl; + std::cout << (co_await executor->Send(*chain, {}, token, 0, data.size() == 0 ? + transfer(target, amount) : transferAndCall(target, amount, data))).hex() << std::endl; - } else if (command == "transferv") { + } else if (command == "erc20:transferv") { orc_assert(nonce_); const auto [token, multiple] = Options(args); @@ -885,8 +785,8 @@ task Main(int argc, const char *const argv[]) { try { const auto comma(Find(line, {','})); orc_assert(comma); - auto [recipient, amount] = Split(line, *comma); - const auto &send(sends.emplace_back(std::string(recipient), uint256_t(Option::_(amount) * Decimal(multiple)))); + auto [target, amount] = Split(line, *comma); + const auto &send(sends.emplace_back(std::string(target), uint256_t(Option(amount) * Decimal(multiple)))); std::cout << "transfer " << token << " " << std::get<0>(send) << " " << std::get<1>(send) << " 0x" << std::endl; total += std::get<1>(send); } @@ -894,48 +794,261 @@ task Main(int argc, const char *const argv[]) { try { std::cout << "total = " << total << std::endl; static Selector> transferv("transferv"); - std::cout << (co_await executor_->Send(*chain_, {.nonce = nonce_}, TransferV, 0, transferv(token, sends))).hex() << std::endl; + std::cout << (co_await executor->Send(*chain, {.nonce = nonce_}, TransferV, 0, transferv(token, sends))).hex() << std::endl; - } else if (command == "uniswap2") { - const auto [pool] = Options
(args); - std::cout << co_await Uniswap2(*chain_, pool, 1) << std::endl; + } else if (command == "lottery0:push") { + const auto [lottery, signer, balance, escrow] = Options(args); + static Selector push("push"); + std::cout << (co_await executor->Send(*chain, {.gas = 175000}, lottery, 0, push(signer, balance + escrow, escrow))).hex() << std::endl; - } else if (command == "uniswap3") { - const auto [pool] = Options
(args); - std::cout << co_await Uniswap3(*chain_, pool, 1) << std::endl; + } else if (command == "lottery1:edit") { + const auto [lottery, amount, signer, adjust, lock, retrieve] = Options(args); + static Selector edit("edit"); + std::cout << (co_await executor->Send(*chain, {}, lottery, amount, edit(signer, adjust, lock, retrieve))).hex() << std::endl; - } else if (command == "unwrap") { - const auto [token, amount] = Options(args); - static Selector withdraw("withdraw"); - std::cout << (co_await executor_->Send(*chain_, {.nonce = nonce_, .gas = gas_}, token, amount, withdraw(amount))).hex() << std::endl; + } else if (command == "lottery1:mark") { + const auto [lottery, token, signer, marked] = Options(args); + static Selector mark("mark"); + std::cout << (co_await executor->Send(*chain, {}, lottery, 0, mark(token, signer, marked))).hex() << std::endl; - } else if (command == "value") { - const auto [address] = Options
(args); - const auto [account] = co_await chain_->Get(co_await block(), address, nullptr); - std::cout << Float(account.balance_) * co_await Binance(*base_, currency_ + "USDT", Ten18) << std::endl; + } else if (command == "multisig:confirm") { + const auto [address, index] = Options(args); + static Selector confirmTransaction("confirmTransaction"); + std::cout << (co_await executor->Send(*chain, {.gas = gas_}, address, 0, confirmTransaction(index))).hex() << std::endl; - } else if (command == "verify") { - auto [height] = Options(args); - do { - co_await chain_->Header(height); - if (height % 1000 == 0) - std::cerr << height << std::endl; - } while (height-- != 0); + } else if (command == "multisig:execute") { + const auto [address, index] = Options(args); + static Selector executeTransaction("executeTransaction"); + std::cout << (co_await executor->Send(*chain, {.gas = gas_}, address, 0, executeTransaction(index))).hex() << std::endl; - } else if (command == "wif") { - // https://en.bitcoin.it/wiki/Wallet_import_format - // prefix with 0x80 for mainnet and 0xEF for testnet - // suffix with 0x01 if this will be a compressed key - const auto [data] = Options(args); - std::cout << ToBase58Check(data) << std::endl; + } else if (command == "multisig:revoke") { + const auto [address, index] = Options(args); + static Selector revokeConfirmation("revokeConfirmation"); + std::cout << (co_await executor->Send(*chain, {.gas = gas_}, address, 0, revokeConfirmation(index))).hex() << std::endl; + + } else if (command == "orchid:pull") { + const auto [stakee, amount, index] = Options(args); + static Selector pull("pull"); + std::cout << (co_await executor->Send(*chain, {}, Directory_, 0, pull(stakee, amount, index))).hex() << std::endl; + + } else if (command == "orchid:take") { + const auto [index, amount, target] = Options(args); + static Selector take("take"); + std::cout << (co_await executor->Send(*chain, {}, Directory_, 0, take(index, amount, target))).hex() << std::endl; + + } else if (command == "run") { + const auto [code, target, amount, data] = Options, uint256_t, Bytes>(args); + const auto contract(target ? *target : Address(Random<20>())); + std::cout << Str(co_await chain->Call("eth_call", {Multi{ + {"from", executor->operator Address()}, + {"to", contract}, + {"gas", gas_}, + {"gasPrice", flags_.bid_}, + {"value", amount}, + {"data", data}, + }, *height_, Multi{ + {executor->operator Address().str(), Multi{{"balance", amount}}}, + {contract.str(), Multi{{"code", code}}}, + }})) << std::endl; + + } else if (command == "seller:allow1") { + const auto [seller, token, allowance, sender] = Options(args); + static Selector> allow("allow"); + std::cout << (co_await executor->Send(*chain, {}, seller, 0, allow(token, allowance, {sender}))).hex() << std::endl; + + } else if (command == "seller:enroll1") { + const auto [seller, cancel, target] = Options(args); + static Selector> enroll("enroll"); + std::cout << (co_await executor->Send(*chain, {}, seller, 0, enroll(cancel, {target}))).hex() << std::endl; + + } else if (command == "seller:giftv") { + orc_assert(nonce_); + const auto [seller] = Options
(args); + + typedef std::tuple Gift; + std::vector gifts; + uint256_t total(0); + + const auto csv(Load(std::to_string(uint64_t(*nonce_)) + ".csv")); + for (auto line : Split(csv, {'\n'})) { + if (line.empty() || line[0] == '#') + continue; + if (line[line.size() - 1] == '\r') { + line -= 1; + if (line.empty()) + continue; + } + + const auto comma0(Find(line, {','})); + orc_assert(comma0); + auto [recipient, rest] = Split(line, *comma0); + + const auto comma1(Find(rest, {','})); + orc_assert(comma1); + auto [amount$, escrow$] = Split(rest, *comma1); + + const uint256_t amount{std::string(amount$)}; + const uint256_t escrow{std::string(escrow$)}; + + const auto combined(amount + escrow); + orc_assert(combined >= escrow); + + const auto &gift(gifts.emplace_back(std::string(recipient), combined, escrow)); + std::cout << "gift " << seller << " " << std::get<0>(gift) << " " << std::get<1>(gift) << " " << std::get<2>(gift) << std::endl; + total += std::get<1>(gift); + } + + std::cout << "total = " << total << std::endl; + + static Selector> giftv("giftv"); + std::cout << (co_await executor->Send(*chain, {.nonce = nonce_}, seller, total, giftv(gifts))).hex() << std::endl; + + } else if (command == "seller:hand") { + const auto [seller, owner, manager] = Options(args); + static Selector hand("hand"); + std::cout << (co_await executor->Send(*chain, {}, seller, 0, hand(owner, manager))).hex() << std::endl; + + } else if (command == "seller:move") { + const auto [url, tls, gpg] = Options(args); + static Selector move("move"); + std::cout << (co_await executor->Send(*chain, {.nonce = nonce_}, "0xEF7bc12e0F6B02fE2cb86Aa659FdC3EBB727E0eD", 0, move(url, tls, gpg))).hex() << std::endl; + + } else if (command == "send") { + const auto [target, amount, data] = Options, uint256_t, Bytes>(args); + std::cout << (co_await executor->Send(*chain, {.nonce = nonce_, .gas = gas_}, target, amount, data)).hex() << std::endl; + + // XXX: these should be generalized and these addresses both calculated and moved into Option_
+ } else if (command == "singleton-100") { + auto [code, salt] = Options(args); + static Selector deploy("deploy"); + static Address factory("0xce0042B868300000d44A59004Da54A005ffdcf9f"); + std::cout << (co_await executor->Send(*chain, {.gas = 3000000}, factory, 0, deploy(code, salt))).hex() << std::endl; + + } else if (command == "singleton-500") { + auto [code, salt] = Options(args); + static Selector deploy("deploy"); + static Address factory("0xe14b5ae0d1e8a4e9039d40e5bf203fd21e2f6241"); + std::cout << (co_await executor->Send(*chain, {.gas = 3000000}, factory, 0, deploy(code, salt))).hex() << std::endl; + + } else if (command == "this") { + Options<>(args); + std::cout << executor->operator Address() << std::endl; + + } else if (command == "unwrap") { + const auto [token, amount] = Options(args); + static Selector withdraw("withdraw"); + std::cout << (co_await executor->Send(*chain, {.nonce = nonce_, .gas = gas_}, token, amount, withdraw(amount))).hex() << std::endl; } else if (command == "wrap") { const auto [token, amount] = Options(args); static Selector deposit("deposit"); - std::cout << (co_await executor_->Send(*chain_, {.nonce = nonce_, .gas = gas_}, token, 0, deposit())).hex() << std::endl; + std::cout << (co_await executor->Send(*chain, {.nonce = nonce_, .gas = gas_}, token, 0, deposit())).hex() << std::endl; - } else orc_assert_(false, "unknown command " << command); + } else co_return co_await Command(command, args, chain); +} + +task CommandChain(Args &args, const S &chain) { + if (!height_) height_ = co_await chain->Height(); + + const auto command(args()); + if (false) { + +#if 0 + } else if (command == "keystore") { + const auto json(Parse(Load(arg.substr(1)))); + std::cout << json << std::endl; + co_return co_await CommandExecutor(args, chain_, executor_); +#endif + + } else if (command == "manual") { + const auto address(Option
(args())); + executor_ = Make(address); + co_return co_await CommandExecutor(args, chain_, executor_); + + } else if (command == "personal") { + const auto address(Option
(args())); + const auto password(Option(args())); + executor_ = Make(address, password); + co_return co_await CommandExecutor(args, chain_, executor_); + + } else if (command == "secret") { + const auto secret(Option(args())); + executor_ = Make(secret); + co_return co_await CommandExecutor(args, chain_, executor_); + + } else if (command == "trezor") { + auto arg(args()); + orc_assert(boost::algorithm::starts_with(arg, "m/")); + + std::vector indices; + arg = arg.substr(2); + for (const auto &span : Split(arg, {'/'})) { + std::string index(span); + orc_assert(!index.empty()); + bool flag; + if (index[index.size() - 1] != '\'') + flag = false; + else { + flag = true; + index = index.substr(0, index.size() - 1); + } + indices.push_back(To(index) | (flag ? 1 << 31 : 0)); + } + auto session(co_await TrezorSession::New(base_)); + executor_ = co_await TrezorExecutor::New(std::move(session), indices); + co_return co_await CommandExecutor(args, chain_, executor_); + + } else if (command == "unlocked") { + const auto address(Option
(args())); + executor_ = Make(address); + co_return co_await CommandExecutor(args, chain_, executor_); + + } else co_return co_await Command(command, args, chain); +} + +task CommandEvm(Args &args) { + const auto rpc(args()); + chain_ = co_await Chain::New(Endpoint{rpc, base_}, flags_); + co_return co_await CommandChain(args, chain_); +} + +task CommandMain(const std::string &command, Args &args) { + if (false) { + + } else if (command == "evm") { + co_return co_await CommandEvm(args); + + } else co_return co_await Command(command, args); +} + +task Main(int argc, const char *const argv[]) { try { + Args args(argc - 1, argv + 1); + + #define ORC_PARAM(name, prefix, suffix) \ + else if (arg == "--" #name) { \ + static bool seen; \ + orc_assert(!seen); \ + seen = true; \ + prefix name##suffix = Option(args()); \ + } + + const auto command([&]() { for (;;) { + auto arg(args()); + orc_assert(!arg.empty()); + if (arg[0] != '-') + return arg; + if (false); + ORC_PARAM(bid,flags_.,_) + ORC_PARAM(height,,_) + ORC_PARAM(currency,,_) + ORC_PARAM(gas,,_) + ORC_PARAM(nonce,,_) + ORC_PARAM(verbose,flags_.,_) + } }()); + + base_ = Break(); + co_await CommandMain(command, args); co_return 0; } catch (const std::exception &error) { std::cerr << error.what() << std::endl; diff --git a/lib-protocol/source/executor.cpp b/lib-protocol/source/executor.cpp index c9e43490d..7d1905f95 100644 --- a/lib-protocol/source/executor.cpp +++ b/lib-protocol/source/executor.cpp @@ -20,23 +20,21 @@ /* }}} */ -#include "messages-ethereum.pb.h" - #include "executor.hpp" #include "nested.hpp" namespace orc { -task Executor::Send(const Chain &chain, Execution execution, const std::optional
&target, const uint256_t &value, const Buffer &data) const { orc_block({ +task SimpleExecutor::Send(const Chain &chain, Execution execution, const std::optional
&target, const uint256_t &value, const Buffer &data) const { orc_block({ const auto bid(execution.bid ? *execution.bid : co_await chain.Bid()); - co_return co_await Send(chain, execution.nonce, bid, execution.gas ? *execution.gas : To((co_await chain("eth_estimateGas", {Multi{ + co_return co_await Send_(chain, execution.nonce, bid, execution.gas ? *execution.gas : To((co_await chain("eth_estimateGas", {Multi{ {"from", operator Address()}, {"gasPrice", bid}, {"to", target}, {"value", value}, {"data", data}, }})).asString()), target, value, data); -}, "sending " << data << " to " << target); } +}, "sending " << data << " with " << value << " to " << target); } MissingExecutor::operator Address() const { @@ -47,10 +45,29 @@ task MissingExecutor::operator ()(const Chain &chain, const Buffer &d orc_assert(false); } -task MissingExecutor::Send(const Chain &chain, const std::optional &nonce, const uint256_t &bid, const uint64_t &gas, const std::optional
&target, const uint256_t &value, const Buffer &data) const { +task MissingExecutor::Send_(const Chain &chain, const std::optional &nonce, const uint256_t &bid, const uint64_t &gas, const std::optional
&target, const uint256_t &value, const Buffer &data) const { + orc_assert(false); +} + + +ManualExecutor::ManualExecutor(Address address) : + address_(std::move(address)) +{ +} + +ManualExecutor::operator Address() const { + return address_; +} + +task ManualExecutor::operator ()(const Chain &chain, const Buffer &data) const { orc_assert(false); } +task ManualExecutor::Send_(const Chain &chain, const std::optional &nonce, const uint256_t &bid, const uint64_t &gas, const std::optional
&target, const uint256_t &value, const Buffer &data) const { + std::cout << "send " << (target ? *target : std::string("null")) << " " << value << " " << data << " --gas " << gas << std::endl; + co_return Zero<32>(); +} + UnlockedExecutor::UnlockedExecutor(Address address) : address_(std::move(address)) @@ -65,7 +82,7 @@ task UnlockedExecutor::operator ()(const Chain &chain, const Buffer & co_return Signature(Bless((co_await chain("eth_sign", {address_, data})).asString())); } -task UnlockedExecutor::Send(const Chain &chain, const std::optional &nonce, const uint256_t &bid, const uint64_t &gas, const std::optional
&target, const uint256_t &value, const Buffer &data) const { +task UnlockedExecutor::Send_(const Chain &chain, const std::optional &nonce, const uint256_t &bid, const uint64_t &gas, const std::optional
&target, const uint256_t &value, const Buffer &data) const { co_return co_await chain.Send("eth_sendTransaction", {Multi{ {"from", address_}, {"nonce", nonce}, @@ -92,7 +109,7 @@ task PasswordExecutor::operator ()(const Chain &chain, const Buffer & co_return Signature(Bless((co_await chain("personal_sign", {address_, data, password_})).asString())); } -task PasswordExecutor::Send(const Chain &chain, const std::optional &nonce, const uint256_t &bid, const uint64_t &gas, const std::optional
&target, const uint256_t &value, const Buffer &data) const { +task PasswordExecutor::Send_(const Chain &chain, const std::optional &nonce, const uint256_t &bid, const uint64_t &gas, const std::optional
&target, const uint256_t &value, const Buffer &data) const { co_return co_await chain.Send("personal_sendTransaction", {Multi{ {"from", address_}, {"nonce", nonce}, @@ -109,9 +126,9 @@ task BasicExecutor::Send(const Chain &chain, const Buffer &data) const co_return co_await chain.Send("eth_sendRawTransaction", {data}); } -task BasicExecutor::Send(const Chain &chain, const std::optional &nonce, const uint256_t &bid, const uint64_t &gas, const std::optional
&target, const uint256_t &value, const Buffer &data) const { +task BasicExecutor::Send_(const Chain &chain, const std::optional &nonce, const uint256_t &bid, const uint64_t &gas, const std::optional
&target, const uint256_t &value, const Buffer &data) const { const auto count(nonce ? *nonce : uint256_t((co_await chain("eth_getTransactionCount", {operator Address(), "latest"})).asString())); - co_return co_await Send(chain, count, bid, gas, target, value, data, true); + co_return co_await Send_(chain, count, bid, gas, target, value, data, true); } @@ -128,7 +145,7 @@ task SecretExecutor::operator ()(const Chain &chain, const Buffer &da co_return Sign(secret_, HashK(Tie("\x19""Ethereum Signed Message:\n", std::to_string(data.size()), data))); } -task SecretExecutor::Send(const Chain &chain, const uint256_t &nonce, const uint256_t &bid, const uint64_t &gas, const std::optional
&target, const uint256_t &value, const Buffer &data, bool eip155) const { +task SecretExecutor::Send_(const Chain &chain, const uint256_t &nonce, const uint256_t &bid, const uint64_t &gas, const std::optional
&target, const uint256_t &value, const Buffer &data, bool eip155) const { co_return co_await BasicExecutor::Send(chain, Subset([&]() { if (eip155) { const auto signature(Sign(secret_, HashK(Implode({nonce, bid, gas, target, value, data, chain.operator const uint256_t &(), uint256_t(0), uint256_t(0)})))); return Implode({nonce, bid, gas, target, value, data, signature.v_ + 35 + 2 * chain.operator const uint256_t &(), signature.r_, signature.s_}); diff --git a/lib-protocol/source/executor.hpp b/lib-protocol/source/executor.hpp index 67ae47e45..6446075f8 100644 --- a/lib-protocol/source/executor.hpp +++ b/lib-protocol/source/executor.hpp @@ -39,26 +39,48 @@ class Executor { virtual operator Address() const = 0; virtual task operator ()(const Chain &chain, const Buffer &data) const = 0; + virtual task Send(const Chain &chain, Execution execution, const std::optional
&target, const uint256_t &value, const Buffer &data) const = 0; +}; - virtual task Send(const Chain &chain, const std::optional &nonce, const uint256_t &bid, const uint64_t &gas, const std::optional
&target, const uint256_t &value, const Buffer &data) const = 0; +class SimpleExecutor : + public Executor +{ + protected: + virtual task Send_(const Chain &chain, const std::optional &nonce, const uint256_t &bid, const uint64_t &gas, const std::optional
&target, const uint256_t &value, const Buffer &data) const = 0; - task Send(const Chain &chain, Execution execution, const std::optional
&target, const uint256_t &value, const Buffer &data) const; + public: + task Send(const Chain &chain, Execution execution, const std::optional
&target, const uint256_t &value, const Buffer &data) const override; }; class MissingExecutor : - public Executor + public SimpleExecutor { public: operator Address() const override; task operator ()(const Chain &chain, const Buffer &data) const override; - task Send(const Chain &chain, const std::optional &nonce, const uint256_t &bid, const uint64_t &gas, const std::optional
&target, const uint256_t &value, const Buffer &data) const override; + protected: + task Send_(const Chain &chain, const std::optional &nonce, const uint256_t &bid, const uint64_t &gas, const std::optional
&target, const uint256_t &value, const Buffer &data) const override; +}; - using Executor::Send; +class ManualExecutor : + public SimpleExecutor +{ + private: + const Address address_; + + public: + ManualExecutor(Address address); + + operator Address() const override; + task operator ()(const Chain &chain, const Buffer &data) const override; + + protected: + task Send_(const Chain &chain, const std::optional &nonce, const uint256_t &bid, const uint64_t &gas, const std::optional
&target, const uint256_t &value, const Buffer &data) const override; }; class UnlockedExecutor : - public Executor + public SimpleExecutor { private: const Address address_; @@ -69,13 +91,12 @@ class UnlockedExecutor : operator Address() const override; task operator ()(const Chain &chain, const Buffer &data) const override; - task Send(const Chain &chain, const std::optional &nonce, const uint256_t &bid, const uint64_t &gas, const std::optional
&target, const uint256_t &value, const Buffer &data) const override; - - using Executor::Send; + protected: + task Send_(const Chain &chain, const std::optional &nonce, const uint256_t &bid, const uint64_t &gas, const std::optional
&target, const uint256_t &value, const Buffer &data) const override; }; class PasswordExecutor : - public Executor + public SimpleExecutor { private: const Address address_; @@ -87,20 +108,20 @@ class PasswordExecutor : operator Address() const override; task operator ()(const Chain &chain, const Buffer &data) const override; - task Send(const Chain &chain, const std::optional &nonce, const uint256_t &bid, const uint64_t &gas, const std::optional
&target, const uint256_t &value, const Buffer &data) const override; - - using Executor::Send; + protected: + task Send_(const Chain &chain, const std::optional &nonce, const uint256_t &bid, const uint64_t &gas, const std::optional
&target, const uint256_t &value, const Buffer &data) const override; }; class BasicExecutor : - public Executor + public SimpleExecutor { public: task Send(const Chain &chain, const Buffer &data) const; - virtual task Send(const Chain &chain, const uint256_t &nonce, const uint256_t &bid, const uint64_t &gas, const std::optional
&target, const uint256_t &value, const Buffer &data, bool eip155) const = 0; - task Send(const Chain &chain, const std::optional &nonce, const uint256_t &bid, const uint64_t &gas, const std::optional
&target, const uint256_t &value, const Buffer &data) const override; + using SimpleExecutor::Send; - using Executor::Send; + protected: + virtual task Send_(const Chain &chain, const uint256_t &nonce, const uint256_t &bid, const uint64_t &gas, const std::optional
&target, const uint256_t &value, const Buffer &data, bool eip155) const = 0; + task Send_(const Chain &chain, const std::optional &nonce, const uint256_t &bid, const uint64_t &gas, const std::optional
&target, const uint256_t &value, const Buffer &data) const override; }; class SecretExecutor : @@ -115,9 +136,8 @@ class SecretExecutor : operator Address() const override; task operator ()(const Chain &chain, const Buffer &data) const override; - task Send(const Chain &chain, const uint256_t &nonce, const uint256_t &bid, const uint64_t &gas, const std::optional
&target, const uint256_t &value, const Buffer &data, bool eip155) const override; - - using BasicExecutor::Send; + protected: + task Send_(const Chain &chain, const uint256_t &nonce, const uint256_t &bid, const uint64_t &gas, const std::optional
&target, const uint256_t &value, const Buffer &data, bool eip155) const override; }; } diff --git a/lib-protocol/source/gnosis.cpp b/lib-protocol/source/gnosis.cpp new file mode 100644 index 000000000..c8732adfc --- /dev/null +++ b/lib-protocol/source/gnosis.cpp @@ -0,0 +1,48 @@ +/* Orchid - WebRTC P2P VPN Market (on Ethereum) + * Copyright (C) 2017-2020 The Orchid Authors +*/ + +/* GNU Affero General Public License, Version 3 {{{ */ +/* + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . +**/ +/* }}} */ + + +#include "gnosis.hpp" + +namespace orc { + +GnosisExecutor::GnosisExecutor(Address address, S executor) : + address_(std::move(address)), + executor_(std::move(executor)) +{ +} + +GnosisExecutor::operator Address() const { + return address_; +} + +task GnosisExecutor::operator ()(const Chain &chain, const Buffer &data) const { + orc_assert(false); +} + +task GnosisExecutor::Send(const Chain &chain, Execution execution, const std::optional
&target, const uint256_t &value, const Buffer &data) const { + static Selector submitTransaction("submitTransaction"); + orc_assert_(target, "unsupported multisig contract deployment"); + orc_assert_(*target != Address(), "unsupported multisig send to address 0"); + co_return co_await executor_->Send(chain, std::move(execution), address_, 0, submitTransaction(*target, value, Bytes(data))); +} + +} diff --git a/lib-protocol/source/gnosis.hpp b/lib-protocol/source/gnosis.hpp new file mode 100644 index 000000000..81923ba01 --- /dev/null +++ b/lib-protocol/source/gnosis.hpp @@ -0,0 +1,49 @@ +/* Orchid - WebRTC P2P VPN Market (on Ethereum) + * Copyright (C) 2017-2020 The Orchid Authors +*/ + +/* GNU Affero General Public License, Version 3 {{{ */ +/* + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . +**/ +/* }}} */ + + +#ifndef ORCHID_GNOSIS_HPP +#define ORCHID_GNOSIS_HPP + +#include "executor.hpp" + +namespace orc { + +class GnosisExecutor : + public Executor +{ + private: + const Address address_; + const S executor_; + + public: + GnosisExecutor(Address address, S executor); + + operator Address() const override; + task operator ()(const Chain &chain, const Buffer &data) const override; + + protected: + task Send(const Chain &chain, Execution execution, const std::optional
&target, const uint256_t &value, const Buffer &data) const override; +}; + +} + +#endif//ORCHID_GNOSIS_HPP diff --git a/lib-protocol/source/trezor.cpp b/lib-protocol/source/trezor.cpp index abeb4d111..dc1d909c8 100644 --- a/lib-protocol/source/trezor.cpp +++ b/lib-protocol/source/trezor.cpp @@ -166,7 +166,7 @@ task TrezorExecutor::operator ()(const Chain &chain, const Buffer &da orc_insist(false); } -task TrezorExecutor::Send(const Chain &chain, const uint256_t &nonce, const uint256_t &bid, const uint64_t &gas, const std::optional
&target, const uint256_t &value, const Buffer &data, bool eip155) const { +task TrezorExecutor::Send_(const Chain &chain, const uint256_t &nonce, const uint256_t &bid, const uint64_t &gas, const std::optional
&target, const uint256_t &value, const Buffer &data, bool eip155) const { tzr::ethereum::EthereumSignTx request; Trezor(request, indices_); request.set_nonce(Stripped(nonce)); diff --git a/lib-protocol/source/trezor.hpp b/lib-protocol/source/trezor.hpp index da1df63d2..0781a7a59 100644 --- a/lib-protocol/source/trezor.hpp +++ b/lib-protocol/source/trezor.hpp @@ -61,9 +61,8 @@ class TrezorExecutor : operator Address() const override; task operator ()(const Chain &chain, const Buffer &data) const override; - task Send(const Chain &chain, const uint256_t &nonce, const uint256_t &bid, const uint64_t &gas, const std::optional
&target, const uint256_t &value, const Buffer &data, bool eip155) const override; - - using BasicExecutor::Send; + protected: + task Send_(const Chain &chain, const uint256_t &nonce, const uint256_t &bid, const uint64_t &gas, const std::optional
&target, const uint256_t &value, const Buffer &data, bool eip155) const override; }; }