Skip to content

Commit

Permalink
feat(indexer): add support to send starknet multicall transaction
Browse files Browse the repository at this point in the history
  • Loading branch information
ptisserand committed Apr 19, 2024
1 parent 9a09a0c commit 1e383b4
Show file tree
Hide file tree
Showing 5 changed files with 251 additions and 26 deletions.
100 changes: 91 additions & 9 deletions apps/indexer/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion apps/indexer/refund/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,5 @@ serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
tokio = { version = "1", features = ["full"] }

starklane_indexer = { version = "0.1.0", path= ".."}
starklane_indexer = { version = "0.1.0", path= ".."}
starknet = "0.10.0"
18 changes: 2 additions & 16 deletions apps/indexer/refund/src/bin/extract_refund.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,30 +2,16 @@
use anyhow::{anyhow, Result};
use clap::Parser;

use serde::Serialize;

use starklane_indexer::{price::moralis::MoralisPrice, storage::{extract_database_name, mongo::MongoStore, store::{EventStore, RequestStore}}};

use refund::Refund;

const ENV_PREFIX: &'static str = "INDEXER";
const ENV_SEPARATOR: &'static str = "__"; // "_" can't be used since we have key with '_' in json

#[derive(Serialize, Debug, Clone)]
struct Refund {
#[serde(rename = "Token Address")]
token_address: String,
#[serde(rename = "Recipient")]
dest: String,
#[serde(rename = "Amount")]
amount: f64,
#[serde(rename = "USD")]
amount_usd: f64,
#[serde(rename = "Transaction Hash")]
tx_hash: String
}

#[derive(Parser, Debug)]
#[clap(about = "Get refund")]
#[clap(about = "Extract refund")]
struct Args {
#[clap(long, help = "Mongo db connection string", env = format!("{}{}MONGODB_URI", ENV_PREFIX, ENV_SEPARATOR))]
mongodb: String,
Expand Down
141 changes: 141 additions & 0 deletions apps/indexer/refund/src/bin/send_refund.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
use std::time::Duration;

use anyhow::{anyhow, Result};
use clap::Parser;

use refund::Refund;
use starknet::{
accounts::{Account, Call, ConnectedAccount, ExecutionEncoding, SingleOwnerAccount},
core::{
types::{ExecutionResult, FieldElement, StarknetError},
utils::get_selector_from_name,
},
providers::{jsonrpc::HttpTransport, JsonRpcClient, Provider, ProviderError, Url},
signers::{LocalWallet, SigningKey},
};

#[derive(Parser, Debug)]
#[clap(about = "Send refund")]
struct Args {
#[clap(long, help = "Mongo db connection string", env = "REFUND_MONGODB_URI")]
mongodb: String,

#[clap(long, help = "CSV input file")]
input: String,

#[clap(long, help = "Starknet RPC", env = "STARKNET_RPC")]
rpc: String,

#[clap(
long,
help = "Starknet account address",
env = "STARKNET_ACCOUNT_ADDRESS"
)]
address: String,

#[clap(
long,
help = "Starknet account private key",
env = "STARKNET_PRIVATE_KEY"
)]
private_key: String,
}

fn refund_to_call(refund: &Refund) -> Call {
let selector = get_selector_from_name("transfer").unwrap();
let token_address = FieldElement::from_hex_be(&refund.token_address).unwrap();
let dest = FieldElement::from_hex_be(&refund.dest).unwrap();
let token_decimals = 18;
let decimals = 8;
let amount = refund.amount * (10_u64.pow(decimals) as f64);
let amount = (amount as u128) * (10_u64.pow(token_decimals - decimals) as u128);
// FIXME: for testing purpose!!
let amount = amount / 100;
// FIXME
let amount = FieldElement::from(amount);
Call {
to: token_address,
selector,
calldata: vec![dest, amount, FieldElement::ZERO],
}
}

// From starkli
pub async fn watch_tx<P>(
provider: P,
transaction_hash: FieldElement,
poll_interval: Duration,
) -> Result<()>
where
P: Provider,
{
loop {
match provider.get_transaction_receipt(transaction_hash).await {
Ok(receipt) => match receipt.execution_result() {
ExecutionResult::Succeeded => {
log::info!(
"Transaction {} confirmed",
format!("{:#064x}", transaction_hash)
);

return Ok(());
}
ExecutionResult::Reverted { reason } => {
return Err(anyhow::anyhow!("transaction reverted: {}", reason));
}
},
Err(ProviderError::StarknetError(StarknetError::TransactionHashNotFound)) => {
log::debug!("Transaction not confirmed yet...");
}
Err(err) => return Err(err.into()),
}

tokio::time::sleep(poll_interval).await;
}
}


#[tokio::main]
async fn main() -> Result<()> {
env_logger::init();
let args = Args::parse();

let input = args.input;
let rpc = args.rpc;
let address = args.address;
let private_key = args.private_key;

let provider = JsonRpcClient::new(HttpTransport::new(Url::parse(&rpc).unwrap()));
let signer = LocalWallet::from(SigningKey::from_secret_scalar(
FieldElement::from_hex_be(&private_key).unwrap(),
));
let address = FieldElement::from_hex_be(&address).unwrap();
let chain_id = provider.chain_id().await?;

let account =
SingleOwnerAccount::new(provider, signer, address, chain_id, ExecutionEncoding::New);
log::debug!("Account address: {:?}", account.address());
let mut calls: Vec<Call> = vec![];

let mut rdr = csv::Reader::from_path(input)?;
for elem in rdr.deserialize() {
let refund: Refund = elem?;
log::debug!("{:?}", refund);
let call = refund_to_call(&refund);
calls.push(call);
}
// log::debug!("Calls: {:?}", calls);

let invoke = account
.execute(calls)
.send()
.await
.unwrap();
let provider = account.provider();
log::debug!("Wait for transaction: {:?}", invoke.transaction_hash);
let result = watch_tx(provider, invoke.transaction_hash, Duration::from_millis(10000)).await;
match result {
Ok(_) => Ok(()),
Err(e) => Err(anyhow!("Transaction failed! {:?}", e))
}
}
15 changes: 15 additions & 0 deletions apps/indexer/refund/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
use serde::{Deserialize, Serialize};

#[derive(Deserialize, Serialize, Debug, Clone)]
pub struct Refund {
#[serde(rename = "Token Address")]
pub token_address: String,
#[serde(rename = "Recipient")]
pub dest: String,
#[serde(rename = "Amount")]
pub amount: f64,
#[serde(rename = "USD")]
pub amount_usd: f64,
#[serde(rename = "Transaction Hash")]
pub tx_hash: String
}

0 comments on commit 1e383b4

Please sign in to comment.