Skip to content

Commit

Permalink
distributor
Browse files Browse the repository at this point in the history
  • Loading branch information
scx1332 committed Mar 16, 2024
1 parent d82a363 commit cc2c97d
Show file tree
Hide file tree
Showing 7 changed files with 230 additions and 34 deletions.
70 changes: 69 additions & 1 deletion crates/erc20_payment_lib/contracts/distributor.json
Original file line number Diff line number Diff line change
@@ -1 +1,69 @@
[{"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"}]
[
{
"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"
}
]
23 changes: 22 additions & 1 deletion crates/erc20_payment_lib/src/contracts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use web3::contract::tokens::Tokenize;
use web3::contract::Contract;
use web3::transports::Http;
use web3::types::{Address, U256};
use web3::{Transport, Web3};
use web3::{ethabi, Transport, Web3};

// todo remove DUMMY_RPC_PROVIDER and use ABI instead
// todo change to once_cell
Expand Down Expand Up @@ -74,6 +74,27 @@ pub fn encode_erc20_allowance(
contract_encode(&ERC20_CONTRACT_TEMPLATE, "allowance", (owner, spender))
}

pub fn encode_distribute(
recipients: &[Address],
amounts: &[U256],
) -> Result<Vec<u8>, web3::ethabi::Error> {
if recipients.len() != amounts.len() {
return Err(web3::ethabi::Error::InvalidData);
}
let mut bytes = Vec::with_capacity(recipients.len() * 20);
for recipient in recipients {
bytes.extend_from_slice(recipient.as_bytes());
}
// convert to abi encoded bytes
let bytes = ethabi::Bytes::from(bytes);

contract_encode(
&DISTRIBUTOR_CONTRACT_TEMPLATE,
"distribute",
(bytes, amounts.to_vec()),
)
}

pub fn encode_faucet_create() -> Result<Vec<u8>, web3::ethabi::Error> {
contract_encode(&FAUCET_CONTRACT_TEMPLATE, "create", ())
}
Expand Down
74 changes: 63 additions & 11 deletions crates/erc20_payment_lib/src/runtime.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::signer::{Signer, SignerAccount};
use crate::transaction::{
create_faucet_mint, create_make_deposit, create_terminate_deposit, create_token_transfer,
find_receipt_extended, FindReceiptParseResult,
create_distribute_transaction, create_faucet_mint, create_make_deposit,
create_terminate_deposit, create_token_transfer, find_receipt_extended, FindReceiptParseResult,
};
use crate::{err_custom_create, err_from};
use erc20_payment_lib_common::create_sqlite_connection;
Expand Down Expand Up @@ -963,12 +963,11 @@ impl PaymentRuntime {
chain_cfg.mint_contract.clone().map(|c| c.address),
false,
)
.await;
.await;
self.wake.notify_one();
res
}


pub async fn mint_golem_token(
&self,
chain_name: &str,
Expand Down Expand Up @@ -1056,23 +1055,77 @@ impl VerifyTransactionResult {
}
}

#[allow(clippy::too_many_arguments)]
pub async fn distribute_gas(
web3: Arc<Web3RpcPool>,
conn: &SqlitePool,
chain_id: u64,
from: Address,
faucet_contract_address: Option<Address>,
distribute_contract_address: Option<Address>,
skip_balance_check: bool,
recipients: &[Address],
amounts: &[rust_decimal::Decimal],
) -> Result<(), PaymentError> {
let faucet_contract_address = if let Some(faucet_contract_address) = faucet_contract_address {
faucet_contract_address
} else {
let distribute_contract_address =
if let Some(distribute_contract_address) = distribute_contract_address {
distribute_contract_address
} else {
return Err(err_custom_create!(
"Distribute contract address unknown. If not sure try on holesky network"
));
};

if recipients.len() != amounts.len() {
return Err(err_custom_create!(
"Faucet/mint contract address unknown. If not sure try on holesky network"
"recipients and amounts must have the same length"
));
};
}

let mut amounts_u256: Vec<U256> = Vec::with_capacity(amounts.len());

let mut sum_u256 = U256::zero();
for amount in amounts {
let amount = amount
.to_u256_from_eth()
.map_err(|err| err_custom_create!("Invalid amount: {} - {}", amount, err))?;
amounts_u256.push(amount);
sum_u256 += amount;
}

if !skip_balance_check {
//todo check if we have enough gas + token to distribute
let get_eth_balance = web3
.clone()
.eth_balance(from, None)
.await
.map_err(err_from!())?
.to_eth_saturate();

if get_eth_balance < Decimal::from_f64(0.000001).unwrap() {
return Err(err_custom_create!(
"You need at least 0.000001 ETH to continue. You have {} ETH on network with chain id: {} and account {:#x} ",
get_eth_balance,
chain_id,
from
));
}
}

let distribute_tx = create_distribute_transaction(
from,
distribute_contract_address,
chain_id,
None,
recipients,
&amounts_u256,
)?;
let distribute_tx = insert_tx(conn, &distribute_tx).await.map_err(err_from!())?;

log::info!(
"Distribute transaction added to queue: {}",
distribute_tx.id
);
Ok(())
}

pub async fn mint_golem_token(
Expand Down Expand Up @@ -1412,7 +1465,6 @@ pub async fn make_deposit(
Ok(())
}


pub async fn get_token_balance(
web3: Arc<Web3RpcPool>,
token_address: Address,
Expand Down
21 changes: 21 additions & 0 deletions crates/erc20_payment_lib/src/transaction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -327,6 +327,27 @@ pub fn create_erc20_transfer_multi(multi_args: MultiTransferArgs) -> Result<TxDb
})
}

pub fn create_distribute_transaction(
from: Address,
faucet_address: Address,
chain_id: u64,
gas_limit: Option<u64>,
recipients: &[Address],
amounts: &[U256],
) -> Result<TxDbObj, PaymentError> {
Ok(TxDbObj {
method: "DISTRIBUTOR.distribute".to_string(),
from_addr: format!("{from:#x}"),
to_addr: format!("{faucet_address:#x}"),
chain_id: chain_id as i64,
gas_limit: gas_limit.map(|gas_limit| gas_limit as i64),
call_data: Some(hex::encode(
encode_distribute(recipients, amounts).map_err(err_from!())?,
)),
..Default::default()
})
}

pub fn create_faucet_mint(
from: Address,
faucet_address: Address,
Expand Down
7 changes: 6 additions & 1 deletion crates/erc20_rpc_pool/src/rpc_pool/eth_generic_call.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,12 @@ impl Web3RpcPool {
}
return Err(web3::Error::Rpc(e));
} else {
log::warn!("Unknown RPC error when calling {} from endpoint {}: {}", EthMethodCall::METHOD, self.get_name(idx),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(),
Expand Down
57 changes: 41 additions & 16 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@ use crate::stats::{export_stats, run_stats};
use erc20_payment_lib::faucet_client::faucet_donate;
use erc20_payment_lib::misc::gen_private_keys;
use erc20_payment_lib::runtime::{
get_token_balance, mint_golem_token, remove_last_unsent_transactions, remove_transaction_force,
PaymentRuntimeArgs,
distribute_gas, get_token_balance, mint_golem_token, remove_last_unsent_transactions,
remove_transaction_force, PaymentRuntimeArgs,
};
use erc20_payment_lib::server::web::{runtime_web_scope, ServerData};
use erc20_payment_lib::setup::PaymentSetup;
Expand Down Expand Up @@ -277,9 +277,7 @@ async fn main_internal() -> Result<(), PaymentError> {
} => {
check_rpc_local(check_web3_rpc_options, config).await?;
}
PaymentCommands::Distribute {
distribute_options
} => {
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 {
Expand All @@ -289,27 +287,54 @@ async fn main_internal() -> Result<(), PaymentError> {
} 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 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)?;

let mut recipients = Vec::with_capacity(distribute_options.recipients.len());

for recipient in distribute_options.recipients.split(';') {
let recipient = recipient.trim();
recipients.push(check_address_name(recipient).map_err(|e| {
err_custom_create!("Invalid recipient address {}, {}", recipient, e)
})?);
}

let amounts = distribute_options
.amounts
.split(';')
.map(|s| {
let s = s.trim();
Decimal::from_str(s)
.map_err(|e| err_custom_create!("Invalid amount {}, {}", s, e))
})
.collect::<Result<Vec<Decimal>, PaymentError>>()?;

if amounts.len() != recipients.len() {
return Err(err_custom_create!(
"Number of recipients and amounts must be the same"
));
}

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,
chain_cfg.distributor_contract.clone().map(|c| c.address),
false,
&recipients,
&amounts,
)
.await?;
.await?;
}
PaymentCommands::GetDevEth {
get_dev_eth_options,
Expand Down
12 changes: 8 additions & 4 deletions src/options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -184,15 +184,19 @@ pub struct DistributeOptions {
#[structopt(long = "account-no", help = "Address by index (for convenience)")]
pub account_no: Option<usize>,

#[structopt(short = "r", long = "recipients", help = "Recipient")]
#[structopt(
short = "r",
long = "recipients",
help = "Recipient (semicolon separated)"
)]
pub recipients: String,

#[structopt(
short = "a",
long = "amount",
help = "Amount (decimal, full precision, i.e. 0.01)"
long = "amounts",
help = "Amounts (decimal, full precision, i.e. 0.01;0.002, separate by semicolon)"
)]
pub amounts: Vec<rust_decimal::Decimal>,
pub amounts: String,
}

#[derive(StructOpt)]
Expand Down

0 comments on commit cc2c97d

Please sign in to comment.