diff --git a/crates/erc20_payment_lib/config-payments.toml b/crates/erc20_payment_lib/config-payments.toml index 282f7d26..9ed2c729 100644 --- a/crates/erc20_payment_lib/config-payments.toml +++ b/crates/erc20_payment_lib/config-payments.toml @@ -143,6 +143,7 @@ token = { address = "0x8888888815bf4DB87e57B609A50f938311EEd068", symbol = "tGLM multi-contract = { address = "0xAaAAAaA00E1841A63342db7188abA84BDeE236c7", max-at-once = 10 } mint-contract = { address = "0xFACe100969FF47EB58d2CF603321B581A84bcEaC", max-glm-allowed = 400 } lock-contract = { address = "0xfe1B27Bac0e3Ad39d55C9459ae59894De847dcbf" } +distributor-contract = { address = "0xb7Fb99e86f93dc3047A12932052236d853065173" } faucet-client = { max-eth-allowed = 0.009, faucet-srv = "_holesky-faucet._tcp", faucet-host = "faucet.testnet.golem.network", faucet-lookup-domain = "dev.golem.network", faucet-srv-port = 4002 } confirmation-blocks = 0 block-explorer-url = "https://holesky.etherscan.io" diff --git a/crates/erc20_payment_lib/contracts/distributor.json b/crates/erc20_payment_lib/contracts/distributor.json new file mode 100644 index 00000000..0074c560 --- /dev/null +++ b/crates/erc20_payment_lib/contracts/distributor.json @@ -0,0 +1 @@ +[{"inputs":[{"internalType":"bytes","name":"addrs","type":"bytes"},{"internalType":"uint256[]","name":"values","type":"uint256[]"}],"name":"distribute","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes","name":"addrs","type":"bytes"}],"name":"distributeEqual","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes","name":"addrs","type":"bytes"},{"internalType":"uint32[]","name":"values","type":"uint32[]"}],"name":"distributeEther","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes","name":"addrs","type":"bytes"},{"internalType":"uint64[]","name":"values","type":"uint64[]"}],"name":"distributeGwei","outputs":[],"stateMutability":"payable","type":"function"}] \ No newline at end of file diff --git a/crates/erc20_payment_lib/src/config.rs b/crates/erc20_payment_lib/src/config.rs index 89603757..393f932a 100644 --- a/crates/erc20_payment_lib/src/config.rs +++ b/crates/erc20_payment_lib/src/config.rs @@ -89,6 +89,12 @@ pub struct LockContractSettings { pub address: Address, } +#[derive(Deserialize, Debug, Clone)] +#[serde(rename_all = "kebab-case")] +pub struct DistributorContractSettings { + pub address: Address, +} + #[derive(Deserialize, Debug, Clone)] #[serde(rename_all = "kebab-case")] pub struct FaucetClientSettings { @@ -128,6 +134,7 @@ pub struct Chain { pub multi_contract: Option, pub mint_contract: Option, pub lock_contract: Option, + pub distributor_contract: Option, pub faucet_client: Option, pub transaction_timeout: u64, pub confirmation_blocks: u64, diff --git a/crates/erc20_payment_lib/src/contracts.rs b/crates/erc20_payment_lib/src/contracts.rs index 5c44831d..cec86027 100644 --- a/crates/erc20_payment_lib/src/contracts.rs +++ b/crates/erc20_payment_lib/src/contracts.rs @@ -26,6 +26,8 @@ lazy_static! { }; pub static ref LOCK_CONTRACT_TEMPLATE: Contract = prepare_contract_template(include_bytes!("../contracts/lock_payments.json")).unwrap(); + pub static ref DISTRIBUTOR_CONTRACT_TEMPLATE: Contract = + prepare_contract_template(include_bytes!("../contracts/distributor.json")).unwrap(); } pub fn prepare_contract_template(json_abi: &[u8]) -> Result, PaymentError> { diff --git a/crates/erc20_payment_lib/src/runtime.rs b/crates/erc20_payment_lib/src/runtime.rs index 09b626e5..c2f33f4b 100644 --- a/crates/erc20_payment_lib/src/runtime.rs +++ b/crates/erc20_payment_lib/src/runtime.rs @@ -942,6 +942,33 @@ impl PaymentRuntime { Ok(()) } + pub async fn distribute_gas( + &self, + chain_name: &str, + from: Address, + ) -> Result<(), PaymentError> { + let chain_cfg = self.config.chain.get(chain_name).ok_or(err_custom_create!( + "Chain {} not found in config file", + chain_name + ))?; + let golem_address = chain_cfg.token.address; + let web3 = self.setup.get_provider(chain_cfg.chain_id)?; + + let res = mint_golem_token( + web3, + &self.conn, + chain_cfg.chain_id as u64, + from, + golem_address, + chain_cfg.mint_contract.clone().map(|c| c.address), + false, + ) + .await; + self.wake.notify_one(); + res + } + + pub async fn mint_golem_token( &self, chain_name: &str, @@ -1029,6 +1056,25 @@ impl VerifyTransactionResult { } } +pub async fn distribute_gas( + web3: Arc, + conn: &SqlitePool, + chain_id: u64, + from: Address, + faucet_contract_address: Option
, + skip_balance_check: bool, +) -> Result<(), PaymentError> { + let faucet_contract_address = if let Some(faucet_contract_address) = faucet_contract_address { + faucet_contract_address + } else { + return Err(err_custom_create!( + "Faucet/mint contract address unknown. If not sure try on holesky network" + )); + }; + + +} + pub async fn mint_golem_token( web3: Arc, conn: &SqlitePool, @@ -1366,6 +1412,7 @@ pub async fn make_deposit( Ok(()) } + pub async fn get_token_balance( web3: Arc, token_address: Address, diff --git a/crates/erc20_payment_lib/src/setup.rs b/crates/erc20_payment_lib/src/setup.rs index 555680c4..88a2862d 100644 --- a/crates/erc20_payment_lib/src/setup.rs +++ b/crates/erc20_payment_lib/src/setup.rs @@ -51,6 +51,7 @@ pub struct ChainSetup { pub glm_address: Address, pub multi_contract_address: Option
, pub lock_contract_address: Option
, + pub distribute_contract_address: Option
, pub faucet_setup: FaucetSetup, pub multi_contract_max_at_once: usize, pub transaction_timeout: u64, @@ -301,6 +302,11 @@ impl PaymentSetup { .map(|m| m.max_at_once) .unwrap_or(1), lock_contract_address: chain_config.1.lock_contract.clone().map(|m| m.address), + distribute_contract_address: chain_config + .1 + .distributor_contract + .clone() + .map(|m| m.address), faucet_setup, transaction_timeout: chain_config.1.transaction_timeout, diff --git a/crates/erc20_payment_lib_test/src/config_setup.rs b/crates/erc20_payment_lib_test/src/config_setup.rs index d20fa19d..104326e4 100644 --- a/crates/erc20_payment_lib_test/src/config_setup.rs +++ b/crates/erc20_payment_lib_test/src/config_setup.rs @@ -42,6 +42,7 @@ pub async fn create_default_config_setup(proxy_url_base: &str, proxy_key: &str) }), mint_contract: None, lock_contract: None, + distributor_contract: None, faucet_client: None, transaction_timeout: 25, confirmation_blocks: 1, diff --git a/crates/erc20_rpc_pool/src/rpc_pool/eth_generic_call.rs b/crates/erc20_rpc_pool/src/rpc_pool/eth_generic_call.rs index d85261d5..7d05b39e 100644 --- a/crates/erc20_rpc_pool/src/rpc_pool/eth_generic_call.rs +++ b/crates/erc20_rpc_pool/src/rpc_pool/eth_generic_call.rs @@ -111,7 +111,7 @@ impl Web3RpcPool { } return Err(web3::Error::Rpc(e)); } else { - log::warn!("Unknown RPC error: {}", e); + log::warn!("Unknown RPC error when calling {} from endpoint {}: {}", EthMethodCall::METHOD, self.get_name(idx),e); self.mark_rpc_error( idx, EthMethodCall::METHOD.to_string(), diff --git a/prometheus/metrics.txt b/prometheus/metrics.txt index 650f4a38..a6fd8426 100644 --- a/prometheus/metrics.txt +++ b/prometheus/metrics.txt @@ -1,6 +1,15 @@ -# HELP senders_count Number of distinct receivers -# TYPE senders_count counter -senders_count{chain_id="137", sender="0x09e4f0ae44d5e60d44a8928af7531e6a862290bc"} 19 +# HELP receivers_count Number of distinct receivers +# TYPE receivers_count counter +receivers_count{chain_id="17000", receiver="0x001111a27323e8fba0176393d03714c0f7467e2b"} 30 # HELP erc20_transferred Number of distinct receivers # TYPE erc20_transferred counter -erc20_transferred{chain_id="137", sender="0x09e4f0ae44d5e60d44a8928af7531e6a862290bc"} 0.000000029482970684 +erc20_transferred{chain_id="17000", sender="0x001111a27323e8fba0176393d03714c0f7467e2b"} 0 +# HELP payment_count Number of distinct payments +# TYPE payment_count counter +payment_count{chain_id="17000", sender="0x001111a27323e8fba0176393d03714c0f7467e2b"} 0 +# HELP transaction_count Number of web3 transactions +# TYPE transaction_count counter +transaction_count{chain_id="17000", sender="0x001111a27323e8fba0176393d03714c0f7467e2b"} 4 +# HELP fee_paid Total fee paid +# TYPE fee_paid counter +fee_paid{chain_id="17000", sender="0x001111a27323e8fba0176393d03714c0f7467e2b"} 0 diff --git a/src/main.rs b/src/main.rs index 5987e977..732da283 100644 --- a/src/main.rs +++ b/src/main.rs @@ -75,6 +75,7 @@ async fn main_internal() -> Result<(), PaymentError> { PaymentCommands::MintTestTokens { .. } => {} PaymentCommands::Deposit { .. } => {} PaymentCommands::Transfer { .. } => {} + PaymentCommands::Distribute { .. } => {} PaymentCommands::Balance { .. } => {} PaymentCommands::ImportPayments { .. } => {} PaymentCommands::ScanBlockchain { .. } => {} @@ -276,6 +277,40 @@ async fn main_internal() -> Result<(), PaymentError> { } => { check_rpc_local(check_web3_rpc_options, config).await?; } + PaymentCommands::Distribute { + distribute_options + } => { + let public_addr = if let Some(address) = distribute_options.address { + address + } else if let Some(account_no) = distribute_options.account_no { + *public_addrs + .get(account_no) + .expect("No public adss found with specified account_no") + } else { + *public_addrs.first().expect("No public adss found") + }; + let chain_cfg = config + .chain + .get(&distribute_options.chain_name) + .ok_or(err_custom_create!( + "Chain {} not found in config file", + distribute_options.chain_name + ))?; + + let payment_setup = PaymentSetup::new_empty(&config)?; + let web3 = payment_setup.get_provider(chain_cfg.chain_id)?; + + distribute_gas( + web3, + &conn.clone().unwrap(), + chain_cfg.chain_id as u64, + public_addr, + chain_cfg.token.address, + chain_cfg.mint_contract.clone().map(|c| c.address), + true, + ) + .await?; + } PaymentCommands::GetDevEth { get_dev_eth_options, } => { diff --git a/src/options.rs b/src/options.rs index c47767b9..2be5e4b1 100644 --- a/src/options.rs +++ b/src/options.rs @@ -172,6 +172,29 @@ pub struct WithdrawTokensOptions { pub skip_balance_check: bool, } +#[derive(StructOpt)] +#[structopt(about = "Distribute token (gas) options")] +pub struct DistributeOptions { + #[structopt(short = "c", long = "chain-name", default_value = "holesky")] + pub chain_name: String, + + #[structopt(long = "address", help = "Address (has to have private key)")] + pub address: Option
, + + #[structopt(long = "account-no", help = "Address by index (for convenience)")] + pub account_no: Option, + + #[structopt(short = "r", long = "recipients", help = "Recipient")] + pub recipients: String, + + #[structopt( + short = "a", + long = "amount", + help = "Amount (decimal, full precision, i.e. 0.01)" + )] + pub amounts: Vec, +} + #[derive(StructOpt)] #[structopt(about = "Single transfer options")] pub struct TransferOptions { @@ -412,6 +435,10 @@ pub enum PaymentCommands { #[structopt(flatten)] single_transfer_options: TransferOptions, }, + Distribute { + #[structopt(flatten)] + distribute_options: DistributeOptions, + }, Balance { #[structopt(flatten)] account_balance_options: BalanceOptions,