This repository has been archived by the owner on Jan 8, 2025. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 106
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(alchemy): add alchemy token methods (#1266)
* feat(alchemy): add alchemy token methods * cleanup * fix dep * fix comments * Update Makefile * fix
- Loading branch information
Showing
8 changed files
with
320 additions
and
95 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,11 +1,17 @@ | ||
use crate::models::balance::TokenBalances; | ||
use crate::models::token::{TokenBalances, TokenMetadata}; | ||
use jsonrpsee::core::RpcResult as Result; | ||
use jsonrpsee::proc_macros::rpc; | ||
use reth_primitives::Address; | ||
use reth_primitives::{Address, U256}; | ||
|
||
#[rpc(server, namespace = "alchemy")] | ||
#[async_trait] | ||
pub trait AlchemyApi { | ||
#[method(name = "getTokenBalances")] | ||
async fn token_balances(&self, address: Address, contract_addresses: Vec<Address>) -> Result<TokenBalances>; | ||
|
||
#[method(name = "getTokenMetadata")] | ||
async fn token_metadata(&self, contract_address: Address) -> Result<TokenMetadata>; | ||
|
||
#[method(name = "getTokenAllowance")] | ||
async fn token_allowance(&self, contract_address: Address, owner: Address, spender: Address) -> Result<U256>; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,41 +1,85 @@ | ||
#![allow(clippy::blocks_in_conditions)] | ||
|
||
use futures::future::join_all; | ||
use jsonrpsee::core::{async_trait, RpcResult}; | ||
use reth_primitives::{Address, BlockId, BlockNumberOrTag}; | ||
use reth_primitives::{Address, BlockId, BlockNumberOrTag, U256}; | ||
|
||
use crate::eth_provider::contracts::erc20::EthereumErc20; | ||
use crate::eth_provider::error::EthApiError; | ||
use crate::eth_provider::provider::EthereumProvider; | ||
use crate::eth_rpc::api::alchemy_api::AlchemyApiServer; | ||
use crate::models::balance::TokenBalanceFuture; | ||
use crate::{eth_provider::provider::EthereumProvider, models::balance::TokenBalances}; | ||
use crate::models::token::{TokenBalance, TokenBalances, TokenMetadata}; | ||
|
||
/// The RPC module for the Ethereum protocol required by Kakarot. | ||
#[derive(Debug)] | ||
pub struct AlchemyRpc<P: EthereumProvider> { | ||
/// The provider for interacting with the Ethereum network. | ||
eth_provider: P, | ||
} | ||
|
||
impl<P: EthereumProvider> AlchemyRpc<P> { | ||
/// Creates a new instance of [`AlchemyRpc`]. | ||
pub const fn new(eth_provider: P) -> Self { | ||
Self { eth_provider } | ||
} | ||
} | ||
|
||
#[async_trait] | ||
impl<P: EthereumProvider + Send + Sync + 'static> AlchemyApiServer for AlchemyRpc<P> { | ||
#[tracing::instrument(skip_all, ret, fields(address = %address, token_addresses = ?token_addresses))] | ||
/// Retrieves the token balances for a given address. | ||
#[tracing::instrument(skip_all, ret, fields(address = %address), err)] | ||
async fn token_balances(&self, address: Address, token_addresses: Vec<Address>) -> RpcResult<TokenBalances> { | ||
tracing::info!("Serving alchemy_getTokenBalances"); | ||
|
||
// Set the block ID to the latest block | ||
let block_id = BlockId::Number(BlockNumberOrTag::Latest); | ||
|
||
Ok(TokenBalances { | ||
address, | ||
token_balances: join_all(token_addresses.into_iter().map(|token_address| async move { | ||
// Create a new instance of `EthereumErc20` for each token address | ||
let token = EthereumErc20::new(token_address, &self.eth_provider); | ||
// Retrieve the balance for the given address | ||
let token_balance = token.balance_of(address, block_id).await?; | ||
Ok(TokenBalance { token_address, token_balance }) | ||
})) | ||
.await | ||
.into_iter() | ||
.collect::<Result<Vec<_>, EthApiError>>()?, | ||
}) | ||
} | ||
|
||
/// Retrieves the metadata for a given token. | ||
#[tracing::instrument(skip(self), ret, err)] | ||
async fn token_metadata(&self, token_address: Address) -> RpcResult<TokenMetadata> { | ||
tracing::info!("Serving alchemy_getTokenMetadata"); | ||
|
||
// Set the block ID to the latest block | ||
let block_id = BlockId::Number(BlockNumberOrTag::Latest); | ||
let handles = token_addresses.into_iter().map(|token_addr| { | ||
let token = EthereumErc20::new(token_addr, &self.eth_provider); | ||
let balance = token.balance_of(address, block_id); | ||
// Create a new instance of `EthereumErc20` | ||
let token = EthereumErc20::new(token_address, &self.eth_provider); | ||
|
||
// Await all futures concurrently to retrieve decimals, name, and symbol | ||
let (decimals, name, symbol) = | ||
futures::try_join!(token.decimals(block_id), token.name(block_id), token.symbol(block_id))?; | ||
|
||
TokenBalanceFuture::new(Box::pin(balance), token_addr) | ||
}); | ||
// Return the metadata | ||
Ok(TokenMetadata { decimals, name, symbol }) | ||
} | ||
|
||
let token_balances = join_all(handles).await.into_iter().collect::<Result<Vec<_>, EthApiError>>()?; | ||
/// Retrieves the allowance of a given owner for a spender. | ||
#[tracing::instrument(skip(self), ret, err)] | ||
async fn token_allowance(&self, token_address: Address, owner: Address, spender: Address) -> RpcResult<U256> { | ||
tracing::info!("Serving alchemy_getTokenAllowance"); | ||
|
||
// Set the block ID to the latest block | ||
let block_id = BlockId::Number(BlockNumberOrTag::Latest); | ||
// Create a new instance of `EthereumErc20` | ||
let token = EthereumErc20::new(token_address, &self.eth_provider); | ||
// Retrieve the allowance for the given owner and spender | ||
let allowance = token.allowance(owner, spender, block_id).await?; | ||
|
||
Ok(TokenBalances { address, token_balances }) | ||
// Return the allowance | ||
Ok(allowance) | ||
} | ||
} |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,4 @@ | ||
pub mod balance; | ||
pub mod block; | ||
pub mod felt; | ||
pub mod token; | ||
pub mod transaction; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
use reth_primitives::{Address, U256}; | ||
use serde::{Deserialize, Serialize}; | ||
|
||
/// Represents the balance of a specific ERC20 token. | ||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] | ||
pub struct TokenBalance { | ||
/// The address of the ERC20 token. | ||
pub token_address: Address, | ||
/// The balance of the ERC20 token. | ||
pub token_balance: U256, | ||
} | ||
|
||
/// Represents the balances of multiple ERC20 tokens for a specific address. | ||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] | ||
pub struct TokenBalances { | ||
/// The address for which the token balances are queried. | ||
pub address: Address, | ||
/// A list of token balances associated with the address. | ||
pub token_balances: Vec<TokenBalance>, | ||
} | ||
|
||
/// Represents the metadata (decimals, name, symbol) of an ERC20 token. | ||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] | ||
pub struct TokenMetadata { | ||
/// The number of decimals the token uses. | ||
pub decimals: U256, | ||
/// The name of the token. | ||
pub name: String, | ||
/// The symbol of the token. | ||
pub symbol: String, | ||
} |
Oops, something went wrong.