From 53653e726bc9e3f137c22eed830a517a572dceb1 Mon Sep 17 00:00:00 2001 From: Aki Wu Date: Wed, 14 Jun 2023 09:01:11 +0800 Subject: [PATCH] add faucet support --- .env.sample | 4 +++ src/faucet.rb | 94 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/server.rb | 25 ++++++++++++++ 3 files changed, 123 insertions(+) create mode 100644 src/faucet.rb diff --git a/.env.sample b/.env.sample index 9c28a49..17981af 100644 --- a/.env.sample +++ b/.env.sample @@ -5,5 +5,9 @@ GOERLI_ENDPOINT=https://eth-goerli.g.alchemy.com/v2/ DARWINIA_ENDPOINT=http://g1.dev.darwinia.network:10000 CRAB_ENDPOINT=https://crab-rpc.darwinia.network PANGOLIN_ENDPOINT=https://pangolin-rpc.darwinia.network +PANGORO_ENDPOINT=https://pangoro-rpc.darwinia.network # mongodb MONGODB_URI=mongodb+srv://:@/goerli_pangolin?retryWrites=true&w=majority +# faucet +DROP_PRIVATE_KEY= +DROP_ADDRESS= diff --git a/src/faucet.rb b/src/faucet.rb new file mode 100644 index 0000000..47256ed --- /dev/null +++ b/src/faucet.rb @@ -0,0 +1,94 @@ +require "mongo" +require "eth" +require "json" +include Eth +require "dotenv/load" + +def get_nonce(eth_client, address) + eth_client.eth_get_transaction_count(address)["result"].to_i(16) +end + +# address:index, network:index, dropped_at, username +def drop_allowed?(mongo_client, address, network) + db = mongo_client[:drops] + drop = db.find({ address: address.downcase, network: network }).first + + !drop || drop[:dropped_at] + 24 * 60 * 60 < Time.now.to_i +end + +def do_drop(evm_client, address, network) + tx = build_drop_tx(evm_client, address, network) + evm_client.eth_send_raw_transaction(tx.hex)["result"] +end + +def build_drop_tx(evm_client, address, network) + payload = { + chain_id: network == "pangolin" ? 43 : 45, + nonce: get_nonce(evm_client, "#{ENV["DROP_ADDRESS"]}"), + gas_price: 2000 * Eth::Unit::GWEI, + gas_limit: 210_000, + to: address, + value: 50 * Eth::Unit::ETHER, + } + tx = Eth::Tx.new payload + signer_key = Eth::Key.new priv: "#{ENV["DROP_PRIVATE_KEY"]}" + tx.sign signer_key + tx +end + +def insert_or_update_drop_record(mongo_client, address, network, username, tx_hash) + db = mongo_client[:drops] + + drop = db.find({ address: address.downcase, network: network }).first + + if drop + db.update_one( + { address: address.downcase, network: network }, + { "$set" => { dropped_at: Time.now.to_i, username: username, tx_hash: tx_hash } } + ) + else + db.insert_one({ + address: address.downcase, + network: network, + dropped_at: Time.now.to_i, + username: username, + tx_hash: tx_hash + }) + end +end + +def drop(evm_client, mongo_client, address, network, username) + tx_hash = do_drop(evm_client, address, network) + insert_or_update_drop_record(mongo_client, address, network, username, tx_hash) + tx_hash +end + +# channel for +def run_drop(address, network, username) + mongo_client = Mongo::Client.new( + ENV["MONGODB_URI"], + server_api: { + version: "1", + }, + ) + + if drop_allowed?(mongo_client, address, network) + evm_client = + if network == "pangolin" + Eth::Client::Http.new(ENV["PANGOLIN_ENDPOINT"]) + else + Eth::Client::Http.new(ENV["PANGORO_ENDPOINT"]) + end + + drop(evm_client, mongo_client, address, network, username) + else + raise "Drop not allowed" + end +end + +# client = Eth::Client::Http.new("https://pangolin-rpc.darwinia.network") +# tx = build_drop_tx(client, "0xDa97bC5EE02F33B92A0665620fFE956E21BAEf0f", "pangolin") +# # puts tx.hash +# # puts client.eth_send_raw_transaction(tx.hex)["result"] + +# puts run_drop("0xDa97bC5EE02F33B92A0665620fFE956E21BAEf0f", "pangolin", "test") diff --git a/src/server.rb b/src/server.rb index 1974437..99e7906 100644 --- a/src/server.rb +++ b/src/server.rb @@ -9,6 +9,7 @@ require_relative "./utils" require_relative "./storage" require_relative "./account" +require_relative "./faucet" config = get_config @@ -16,6 +17,30 @@ "Hello Darwinia!" end +post "/faucet" do + network = params["network"] ||= "pangolin" + if not %w[pangolin pangoro].include?(network.downcase) + raise_with( + 404, + "network #{network} not found, only `pangolin` and `pangoro` are supported", + ) + end + + # TODO: check the address is valid + address = params["address"] + unless address + raise_with(400, "address is required") + end + if address !~ /^0x[0-9a-fA-F]{40}$/ + raise_with(400, "address is invalid") + end + + username = params["username"] + + tx_hash = run_drop(address, network, username) + render_json tx_hash +end + ############################################################################## # Darwinia & Crab's supplies ##############################################################################