Skip to content

Commit

Permalink
Move token wallet stuff into nekoton-contracts
Browse files Browse the repository at this point in the history
  • Loading branch information
Rexagon committed Jan 8, 2024
1 parent 08068f6 commit 0f1a118
Show file tree
Hide file tree
Showing 8 changed files with 260 additions and 270 deletions.
2 changes: 2 additions & 0 deletions nekoton-contracts/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,15 @@ edition = "2021"
[dependencies]
anyhow = "1.0"
once_cell = "1.12"
serde = { version = "1.0.183", features = ["derive"] }
thiserror = "1.0"

ton_block = { git = "https://github.com/broxus/ton-labs-block.git" }
ton_types = { git = "https://github.com/broxus/ton-labs-types.git" }
ton_abi = { git = "https://github.com/broxus/ton-labs-abi" }

nekoton-abi = { path = "../nekoton-abi", features = ["derive"] }
nekoton-utils = { path = "../nekoton-utils" }

[features]
web = ["ton_abi/web"]
2 changes: 1 addition & 1 deletion nekoton-contracts/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
#![warn(
missing_copy_implementations,
macro_use_extern_crate,
keyword_idents,
explicit_outlives_requirements,
Expand Down Expand Up @@ -60,6 +59,7 @@ pub mod old_tip3;
pub mod tip1155;
pub mod tip3;
pub mod tip3_1;
pub mod tip3_any;
pub mod tip4_1;
pub mod tip4_2;
pub mod tip4_3;
Expand Down
62 changes: 62 additions & 0 deletions nekoton-contracts/src/tip3_any/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
use nekoton_abi::num_bigint::BigUint;
use nekoton_utils::*;
use serde::{Deserialize, Serialize};
use ton_block::MsgAddressInt;

pub use self::root_token_contract::RootTokenContractState;
pub use self::token_wallet_contract::TokenWalletContractState;

mod root_token_contract;
mod token_wallet_contract;

define_string_enum!(
#[derive(Debug, Copy, Clone, Eq, PartialEq, Serialize, Deserialize)]
pub enum TokenWalletVersion {
/// Third iteration of token wallets, but with fixed bugs
/// [implementation](https://github.com/broxus/ton-eth-bridge-token-contracts/tree/74905260499d79cf7cb0d89a6eb572176fc1fcd5)
OldTip3v4,
/// Latest iteration with completely new standard
/// [implementation](https://github.com/broxus/ton-eth-bridge-token-contracts/tree/9168190f218fd05a64269f5f24295c69c4840d94)
Tip3,
}
);

#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)]
pub struct RootTokenContractDetails {
/// Token ecosystem version
pub version: TokenWalletVersion,
/// Full currency name
pub name: String,
/// Short currency name
pub symbol: String,
/// Decimals
pub decimals: u8,
/// Root owner contract address. Used as proxy address in Tip3v1
#[serde(with = "serde_address")]
pub owner_address: MsgAddressInt,
#[serde(with = "serde_string")]
pub total_supply: BigUint,
}

#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct TokenWalletDetails {
/// Linked root token contract address
#[serde(with = "serde_address")]
pub root_address: MsgAddressInt,

/// Owner wallet address
#[serde(with = "serde_address")]
pub owner_address: MsgAddressInt,

#[serde(with = "serde_string")]
pub balance: BigUint,
}

#[derive(thiserror::Error, Debug)]
pub enum Tip3Error {
#[error("Unknown version")]
UnknownVersion,
#[error("Wallet not deployed")]
WalletNotDeployed,
}
80 changes: 80 additions & 0 deletions nekoton-contracts/src/tip3_any/root_token_contract.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
use nekoton_abi::ExecutionContext;
use ton_block::MsgAddressInt;

use super::{RootTokenContractDetails, Tip3Error, TokenWalletVersion};
use crate::{old_tip3, tip3, tip3_1, tip6};

pub struct RootTokenContractState<'a>(pub ExecutionContext<'a>);

impl RootTokenContractState<'_> {
/// Calculates token wallet address
pub fn get_wallet_address(
&self,
version: TokenWalletVersion,
owner: &MsgAddressInt,
) -> anyhow::Result<MsgAddressInt> {
match version {
TokenWalletVersion::OldTip3v4 => {
old_tip3::RootTokenContract(self.0).get_wallet_address(owner.clone())
}
TokenWalletVersion::Tip3 => tip3_1::RootTokenContract(self.0).wallet_of(owner.clone()),
}
}

/// Tries to guess version and retrieve details
pub fn guess_details(&self) -> anyhow::Result<RootTokenContractDetails> {
if let Ok(true) = tip6::SidContract(self.0).supports_interfaces(&[
tip3::root_token_contract::INTERFACE_ID,
tip3_1::root_token_contract::INTERFACE_ID,
]) {
return self.get_details(TokenWalletVersion::Tip3);
}

let version = match old_tip3::RootTokenContract(self.0).get_version()? {
4 => TokenWalletVersion::OldTip3v4,
_ => anyhow::bail!(Tip3Error::UnknownVersion),
};

self.get_details(version)
}

/// Retrieve details using specified version
pub fn get_details(
&self,
version: TokenWalletVersion,
) -> anyhow::Result<RootTokenContractDetails> {
Ok(match version {
TokenWalletVersion::OldTip3v4 => {
let details = old_tip3::RootTokenContract(self.0).get_details()?;

RootTokenContractDetails {
version,
name: details.name,
symbol: details.symbol,
decimals: details.decimals,
owner_address: details.root_owner_address,
total_supply: details.total_supply,
}
}
TokenWalletVersion::Tip3 => {
let root_contract = tip3::RootTokenContract(self.0);
let name = root_contract.name()?;
let symbol = root_contract.symbol()?;
let decimals = root_contract.decimals()?;
let total_supply = root_contract.total_supply()?;

let root_contract = tip3_1::RootTokenContract(self.0);
let owner_address = root_contract.root_owner()?;

RootTokenContractDetails {
version,
name,
symbol,
decimals,
owner_address,
total_supply,
}
}
})
}
}
71 changes: 71 additions & 0 deletions nekoton-contracts/src/tip3_any/token_wallet_contract.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
use nekoton_abi::num_bigint::BigUint;
use nekoton_abi::ExecutionContext;

use super::{Tip3Error, TokenWalletDetails, TokenWalletVersion};
use crate::{old_tip3, tip3, tip3_1, tip6};

pub struct TokenWalletContractState<'a>(pub ExecutionContext<'a>);

impl<'a> TokenWalletContractState<'a> {
pub fn get_code_hash(&self) -> anyhow::Result<ton_types::UInt256> {
match &self.0.account_stuff.storage.state {
ton_block::AccountState::AccountActive { state_init, .. } => {
let code = state_init
.code
.as_ref()
.ok_or(Tip3Error::WalletNotDeployed)?;
Ok(code.repr_hash())
}
_ => Err(Tip3Error::WalletNotDeployed.into()),
}
}

pub fn get_balance(&self, version: TokenWalletVersion) -> anyhow::Result<BigUint> {
match version {
TokenWalletVersion::OldTip3v4 => old_tip3::TokenWalletContract(self.0).balance(),
TokenWalletVersion::Tip3 => tip3::TokenWalletContract(self.0).balance(),
}
}

pub fn get_details(&self, version: TokenWalletVersion) -> anyhow::Result<TokenWalletDetails> {
Ok(match version {
TokenWalletVersion::OldTip3v4 => {
let details = old_tip3::TokenWalletContract(self.0).get_details()?;

TokenWalletDetails {
root_address: details.root_address,
owner_address: details.owner_address,
balance: details.balance,
}
}
TokenWalletVersion::Tip3 => {
let token_wallet = tip3::TokenWalletContract(self.0);
let root_address = token_wallet.root()?;
let balance = token_wallet.balance()?;

let token_wallet = tip3_1::TokenWalletContract(self.0);
let owner_address = token_wallet.owner()?;

TokenWalletDetails {
root_address,
owner_address,
balance,
}
}
})
}

pub fn get_version(&self) -> anyhow::Result<TokenWalletVersion> {
if let Ok(true) = tip6::SidContract(self.0).supports_interfaces(&[
tip3::token_wallet_contract::INTERFACE_ID,
tip3_1::token_wallet_contract::INTERFACE_ID,
]) {
return Ok(TokenWalletVersion::Tip3);
}

match old_tip3::TokenWalletContract(self.0).get_version()? {
4 => Ok(TokenWalletVersion::OldTip3v4),
_ => Err(Tip3Error::UnknownVersion.into()),
}
}
}
16 changes: 8 additions & 8 deletions src/core/owners_cache/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@ use serde::Deserialize;
use tokio::sync::{RwLock, Semaphore};
use ton_block::MsgAddressInt;

use nekoton_contracts::tip3_any::{RootTokenContractState, TokenWalletContractState};
use nekoton_utils::*;

use super::models::TokenWalletVersion;
use crate::core::token_wallet::{RootTokenContractState, TokenWalletContractState};
use crate::external::Storage;
use crate::transport::models::{ExistingContract, RawContractState};
use crate::transport::Transport;
Expand Down Expand Up @@ -124,8 +124,8 @@ impl OwnersCache {
}
};

let version = RootTokenContractState(&state)
.guess_details(self.clock.as_ref())?
let version = RootTokenContractState(state.as_context(self.clock.as_ref()))
.guess_details()?
.version;

check_token_wallet(
Expand Down Expand Up @@ -168,9 +168,9 @@ impl OwnersCache {
}
};

let state = TokenWalletContractState(&contract_state);
let version = state.get_version(clock).ok()?;
let details = state.get_details(clock, version).ok()?;
let state = TokenWalletContractState(contract_state.as_context(clock));
let version = state.get_version().ok()?;
let details = state.get_details(version).ok()?;

owners
.write()
Expand Down Expand Up @@ -248,8 +248,8 @@ async fn check_token_wallet(
(state, version): &(ExistingContract, TokenWalletVersion),
owner_wallet: &MsgAddressInt,
) -> Result<RecipientWallet> {
let token_wallet =
RootTokenContractState(state).get_wallet_address(clock, *version, owner_wallet)?;
let token_wallet = RootTokenContractState(state.as_context(clock))
.get_wallet_address(*version, owner_wallet)?;

{
let mut owners = owners.write().await;
Expand Down
Loading

0 comments on commit 0f1a118

Please sign in to comment.