Skip to content

Commit

Permalink
cleanup
Browse files Browse the repository at this point in the history
  • Loading branch information
dr-frmr committed Jul 15, 2024
1 parent f8500a6 commit ab7ad26
Show file tree
Hide file tree
Showing 4 changed files with 170 additions and 150 deletions.
109 changes: 24 additions & 85 deletions src/eth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,9 @@ pub use alloy::rpc::types::{
Block, BlockId, BlockNumberOrTag, FeeHistory, Filter, FilterBlockOption, Log, Transaction,
TransactionReceipt,
};
use alloy_primitives::FixedBytes;
pub use alloy_primitives::{Address, BlockHash, BlockNumber, Bytes, TxHash, U128, U256, U64, U8};
use alloy_sol_macro::sol;
use alloy_sol_types::SolCall;
use serde::{Deserialize, Serialize};
use std::collections::{HashMap, HashSet};
use std::str::FromStr;

//
// types mirrored from runtime module
Expand Down Expand Up @@ -184,20 +180,6 @@ impl std::cmp::PartialEq<str> for NodeOrRpcUrl {
}
}

/// KiMap default address
const KIMAP: &str = "0x0165878A594ca255338adfa4d48449f69242Eb8F";

// Sol structures for KiMap requests
sol! {
function get (
bytes32 entryhash
) external view returns (
address tokenBoundAccount,
address tokenOwner,
bytes data
);
}

/// An EVM chain provider. Create this object to start making RPC calls.
/// Set the chain_id to determine which chain to call: requests will fail
/// unless the node this process is running on has access to a provider
Expand Down Expand Up @@ -572,14 +554,14 @@ impl Provider {
self.send_request_and_parse_response::<Bytes>(action)
}

/// Returns a KiMap instance with the default address using this provider.
pub fn kimap(&self) -> KiMap {
KiMap::default(self)
/// Returns a Kimap instance with the default address using this provider.
pub fn kimap(&self) -> crate::kimap::Kimap {
crate::kimap::Kimap::default(self.request_timeout)
}

/// Returns a KiMap instance with a custom address using this provider.
pub fn kimap_with_address(&self, address: Address) -> KiMap {
KiMap::new(self, address)
/// Returns a Kimap instance with a custom address using this provider.
pub fn kimap_with_address(self, address: Address) -> crate::kimap::Kimap {
crate::kimap::Kimap::new(self, address)
}

/// Sends a raw transaction to the network.
Expand Down Expand Up @@ -640,6 +622,24 @@ impl Provider {
}
}

/// Subscribe in a loop until successful
pub fn subscribe_loop(&self, sub_id: u64, filter: Filter) {
loop {
match self.subscribe(sub_id, filter.clone()) {
Ok(()) => break,
Err(_) => {
crate::print_to_terminal(
0,
"failed to subscribe to chain! trying again in 5s...",
);
std::thread::sleep(std::time::Duration::from_secs(5));
continue;
}
}
}
crate::print_to_terminal(0, "subscribed to logs successfully");
}

/// Unsubscribes from a previously created subscription.
///
/// # Parameters
Expand All @@ -666,64 +666,3 @@ impl Provider {
}
}
}

/// Helper struct for the KiMap.
pub struct KiMap<'a> {
provider: &'a Provider,
address: Address,
}

impl<'a> KiMap<'a> {
/// Creates a new KiMap instance with a specified address.
///
/// # Arguments
/// * `provider` - A reference to the Provider.
/// * `address` - The address of the KiMap contract.
pub fn new(provider: &'a Provider, address: Address) -> Self {
Self { provider, address }
}

/// Creates a new KiMap instance with the default address.
///
/// # Arguments
/// * `provider` - A reference to the Provider.
pub fn default(provider: &'a Provider) -> Self {
Self::new(provider, Self::default_address())
}

/// Returns the default KiMap contract address.
pub fn default_address() -> Address {
Address::from_str(KIMAP).unwrap()
}

/// Gets an entry from the KiMap.
///
/// # Parameters
/// - `entryhash`: The entry to get from the KiMap.
/// # Returns
/// A `Result<(Address, Address, Option<Bytes>), EthError>` representing the TBA, owner, and value if the entry is a note.
pub fn get(&self, entryhash: &str) -> Result<(Address, Address, Option<Bytes>), EthError> {
let get_call = getCall {
entryhash: FixedBytes::<32>::from_str(entryhash)
.map_err(|_| EthError::InvalidParams)?,
}
.abi_encode();

let tx_req = TransactionRequest::default()
.input(TransactionInput::new(get_call.into()))
.to(self.address);

let res_bytes = self.provider.call(tx_req, None)?;

let res = getCall::abi_decode_returns(&res_bytes, false)
.map_err(|_| EthError::RpcMalformedResponse)?;

let note_data = if res.data == Bytes::default() {
None
} else {
Some(res.data)
};

Ok((res.tokenBoundAccount, res.tokenOwner, note_data))
}
}
143 changes: 143 additions & 0 deletions src/kimap.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
use crate::eth::*;
use crate::kimap::contract::getCall;
use alloy::rpc::types::request::{TransactionInput, TransactionRequest};
use alloy::{hex, primitives::keccak256};
use alloy_primitives::FixedBytes;
use alloy_primitives::B256;
use alloy_primitives::{Address, Bytes};
use alloy_sol_types::SolCall;
use alloy_sol_types::SolValue;
use std::str::FromStr;

/// kimap deployment address on optimism
pub const KIMAP_ADDRESS: &'static str = "0x7290Aa297818d0b9660B2871Bb87f85a3f9B4559";
/// optimism chain id
pub const KIMAP_CHAIN_ID: u64 = 10;
/// first block of kimap deployment on optimism
pub const KIMAP_FIRST_BLOCK: u64 = 114_923_786;
/// the root hash of kimap, empty bytes32
pub const KIMAP_ROOT_HASH: &'static str =
"0x0000000000000000000000000000000000000000000000000000000000000000";

// Sol structures for Kimap requests
pub mod contract {
use alloy_sol_macro::sol;

sol! {
event Mint(bytes32 indexed parenthash, bytes32 indexed childhash, bytes indexed labelhash, bytes name);
event Note(bytes32 indexed nodehash, bytes32 indexed notehash, bytes indexed labelhash, bytes note, bytes data);

function get (
bytes32 entryhash
) external view returns (
address tokenBoundAccount,
address tokenOwner,
bytes memory data
);
}
}

pub fn namehash(name: &str) -> String {
let mut node = B256::default();

let mut labels: Vec<&str> = name.split('.').collect();
labels.reverse();

for label in labels.iter() {
let l = keccak256(label);
node = keccak256((node, l).abi_encode_packed());
}
format!("0x{}", hex::encode(node))
}

/// Helper struct for the Kimap.
pub struct Kimap {
pub provider: Provider,
address: Address,
}

impl Kimap {
/// Creates a new Kimap instance with a specified address.
///
/// # Arguments
/// * `provider` - A reference to the Provider.
/// * `address` - The address of the Kimap contract.
pub fn new(provider: Provider, address: Address) -> Self {
Self { provider, address }
}

/// Creates a new Kimap instance with the default address and chain ID.
pub fn default(timeout: u64) -> Self {
let provider = Provider::new(KIMAP_CHAIN_ID, timeout);
Self::new(provider, Address::from_str(KIMAP_ADDRESS).unwrap())
}

/// Returns the in-use Kimap contract address.
pub fn address(&self) -> &Address {
&self.address
}

/// Gets an entry from the Kimap by its string-formatted name.
///
/// # Parameters
/// - `path`: The name-path to get from the Kimap.
/// # Returns
/// A `Result<(Address, Address, Option<Bytes>), EthError>` representing the TBA, owner,
/// and value if the entry exists and is a note.
pub fn get(&self, path: &str) -> Result<(Address, Address, Option<Bytes>), EthError> {
let get_call = getCall {
entryhash: FixedBytes::<32>::from_str(&namehash(path))
.map_err(|_| EthError::InvalidParams)?,
}
.abi_encode();

let tx_req = TransactionRequest::default()
.input(TransactionInput::new(get_call.into()))
.to(self.address);

let res_bytes = self.provider.call(tx_req, None)?;

let res = getCall::abi_decode_returns(&res_bytes, false)
.map_err(|_| EthError::RpcMalformedResponse)?;

let note_data = if res.data == Bytes::default() {
None
} else {
Some(res.data)
};

Ok((res.tokenBoundAccount, res.tokenOwner, note_data))
}

/// Gets an entry from the Kimap by its hash.
///
/// # Parameters
/// - `entryhash`: The entry to get from the Kimap.
/// # Returns
/// A `Result<(Address, Address, Option<Bytes>), EthError>` representing the TBA, owner,
/// and value if the entry exists and is a note.
pub fn get_hash(&self, entryhash: &str) -> Result<(Address, Address, Option<Bytes>), EthError> {
let get_call = getCall {
entryhash: FixedBytes::<32>::from_str(entryhash)
.map_err(|_| EthError::InvalidParams)?,
}
.abi_encode();

let tx_req = TransactionRequest::default()
.input(TransactionInput::new(get_call.into()))
.to(self.address);

let res_bytes = self.provider.call(tx_req, None)?;

let res = getCall::abi_decode_returns(&res_bytes, false)
.map_err(|_| EthError::RpcMalformedResponse)?;

let note_data = if res.data == Bytes::default() {
None
} else {
Some(res.data)
};

Ok((res.tokenBoundAccount, res.tokenOwner, note_data))
}
}
2 changes: 2 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ pub mod http;
/// be incompatible with WIT types in some cases, leading to annoying errors.
/// Use only to interact with the kernel or runtime in certain ways.
pub mod kernel_types;
/// Interact with the kimap module
pub mod kimap;
/// Interact with the key_value module
pub mod kv;
/// Interact with the networking module
Expand Down
66 changes: 1 addition & 65 deletions src/net.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
use crate::{get_blob, println, Address, NodeId, Request, SendError};
use alloy::{hex, primitives::keccak256};
use alloy_primitives::B256;
use alloy_sol_types::SolValue;
use crate::{get_blob, Address, NodeId, Request, SendError};
use serde::{Deserialize, Serialize};
use std::collections::BTreeMap;

Expand Down Expand Up @@ -181,64 +178,3 @@ pub fn get_name(namehash: &str, timeout: Option<u64>) -> anyhow::Result<String>
Err(anyhow::anyhow!("unexpected response: {:?}", response))
}
}

/// namehash... kimap style
pub fn namehash(name: &str) -> String {
let mut node = B256::default();

let mut labels: Vec<&str> = name.split('.').collect();
labels.reverse();

for label in labels.iter() {
let l = keccak256(label);
node = keccak256((node, l).abi_encode_packed());
}
format!("0x{}", hex::encode(node))
}

/// take a DNSwire-formatted node ID from chain and convert it to a String
pub fn dnswire_decode(wire_format_bytes: &[u8]) -> Result<String, DnsDecodeError> {
let mut i = 0;
let mut result = Vec::new();

while i < wire_format_bytes.len() {
let len = wire_format_bytes[i] as usize;
if len == 0 {
break;
}
let end = i + len + 1;
let mut span = match wire_format_bytes.get(i + 1..end) {
Some(span) => span.to_vec(),
None => return Err(DnsDecodeError::FormatError),
};
span.push('.' as u8);
result.push(span);
i = end;
}

let flat: Vec<_> = result.into_iter().flatten().collect();

let name = String::from_utf8(flat).map_err(|e| DnsDecodeError::Utf8Error(e))?;

// Remove the trailing '.' if it exists (it should always exist)
if name.ends_with('.') {
Ok(name[0..name.len() - 1].to_string())
} else {
Ok(name)
}
}

#[derive(Clone, Debug, thiserror::Error)]
pub enum DnsDecodeError {
Utf8Error(std::string::FromUtf8Error),
FormatError,
}

impl std::fmt::Display for DnsDecodeError {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match self {
DnsDecodeError::Utf8Error(e) => write!(f, "UTF-8 error: {}", e),
DnsDecodeError::FormatError => write!(f, "Format error"),
}
}
}

0 comments on commit ab7ad26

Please sign in to comment.