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