Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TransferDomain DST20 refinements #2481

Merged
merged 4 commits into from
Sep 22, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 3 additions & 9 deletions lib/ain-contracts/transfer_domain/TransferDomain.sol
Original file line number Diff line number Diff line change
Expand Up @@ -54,20 +54,16 @@ contract TransferDomain is IERC20Metadata {
uint256 amount,
string memory vmAddress
) external {
address transferFrom = from;

if (to != address(this)) {
require(
address(this).balance >= amount,
"Insufficient contract balance"
);

to.transfer(amount);

transferFrom = address(this);
}

emit Transfer(transferFrom, to, amount);
emit Transfer(from, to, amount);
emit VMTransfer(vmAddress);
}

Expand All @@ -83,7 +79,7 @@ contract TransferDomain is IERC20Metadata {
* name.
*/
function symbol() public view virtual override returns (string memory) {
return "XVM";
return "DFI";
}

/**
Expand All @@ -110,9 +106,7 @@ contract TransferDomain is IERC20Metadata {
uint256 amount,
string memory vmAddress
) external {
if (to != address(this)) {
IERC20(contractAddress).transferFrom(from, to, amount);
}
IERC20(contractAddress).transferFrom(from, to, amount);
emit VMTransfer(vmAddress);
}

Expand Down
88 changes: 62 additions & 26 deletions lib/ain-evm/src/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -143,12 +143,10 @@ pub fn dst20_contract(
})
}

pub fn bridge_dst20(
pub fn bridge_dst20_in(
backend: &EVMBackend,
contract: H160,
from: H160,
amount: U256,
direction: TransferDirection,
) -> Result<DST20BridgeInfo> {
// check if code of address matches DST20 bytecode
let account = backend
Expand All @@ -163,43 +161,81 @@ pub fn bridge_dst20(
}

// balance has slot 0
let balance_storage_index = get_address_storage_index(H256::zero(), from);
let balance = backend.get_contract_storage(contract, balance_storage_index.as_bytes())?;

// allowance has slot 1
let allowance_storage_index = get_address_storage_index(H256::from_low_u64_be(1), from);
let address_allowance_storage_index =
get_address_storage_index(allowance_storage_index, fixed_address);
let contract_balance_storage_index = get_address_storage_index(H256::zero(), fixed_address);

let total_supply_index = H256::from_low_u64_be(2);
let total_supply = backend.get_contract_storage(contract, total_supply_index.as_bytes())?;

let (new_balance, new_total_supply) = if direction == TransferDirection::EvmOut {
(
balance.checked_sub(amount),
total_supply.checked_sub(amount),
)
} else {
(
balance.checked_add(amount),
total_supply.checked_add(amount),
)
};
let new_total_supply = total_supply
.checked_add(amount)
.ok_or_else(|| format_err!("Total supply overflow/underflow"))?;

let new_balance = new_balance.ok_or_else(|| format_err!("Balance overflow/underflow"))?;
let new_total_supply =
new_total_supply.ok_or_else(|| format_err!("Total supply overflow/underflow"))?;
Ok(DST20BridgeInfo {
address: contract,
storage: vec![
(contract_balance_storage_index, u256_to_h256(amount)),
(total_supply_index, u256_to_h256(new_total_supply)),
],
})
}

pub fn bridge_dst20_out(
backend: &EVMBackend,
contract: H160,
amount: U256,
) -> Result<DST20BridgeInfo> {
// check if code of address matches DST20 bytecode
let account = backend
.get_account(&contract)
.ok_or_else(|| format_err!("DST20 token address is not a contract"))?;

let FixedContract { fixed_address, .. } = get_transferdomain_contract();

let Contract { codehash, .. } = get_dst20_contract();
if account.code_hash != codehash {
return Err(format_err!("DST20 token code is not valid").into());
}

let contract_balance_storage_index = get_address_storage_index(H256::zero(), fixed_address);

let total_supply_index = H256::from_low_u64_be(2);
let total_supply = backend.get_contract_storage(contract, total_supply_index.as_bytes())?;

let new_total_supply = total_supply
.checked_sub(amount)
.ok_or_else(|| format_err!("Total supply overflow/underflow"))?;

Ok(DST20BridgeInfo {
address: contract,
storage: vec![
(balance_storage_index, u256_to_h256(new_balance)),
(contract_balance_storage_index, u256_to_h256(U256::zero())), // Reset contract balance to 0
(total_supply_index, u256_to_h256(new_total_supply)),
(address_allowance_storage_index, u256_to_h256(amount)),
],
})
}

pub fn dst20_allowance(
direction: TransferDirection,
from: H160,
amount: U256,
) -> Vec<(H256, H256)> {
let FixedContract { fixed_address, .. } = get_transferdomain_contract();

// allowance has slot 1
let allowance_storage_index = get_address_storage_index(
H256::from_low_u64_be(1),
if direction == TransferDirection::EvmIn {
fixed_address
} else {
from
},
);
let address_allowance_storage_index =
get_address_storage_index(allowance_storage_index, fixed_address);

vec![(address_allowance_storage_index, u256_to_h256(amount))]
}

pub fn bridge_dfi(
backend: &EVMBackend,
amount: U256,
Expand Down
36 changes: 18 additions & 18 deletions lib/ain-evm/src/executor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ use crate::{
backend::EVMBackend,
bytes::Bytes,
contract::{
bridge_dfi, bridge_dst20, dst20_contract, dst20_deploy_contract_tx, DST20BridgeInfo,
DeployContractInfo,
bridge_dfi, bridge_dst20_in, bridge_dst20_out, dst20_allowance, dst20_contract,
dst20_deploy_contract_tx, DST20BridgeInfo, DeployContractInfo,
},
core::EVMCoreService,
evm::ReceiptAndOptionalContractAddress,
Expand Down Expand Up @@ -339,22 +339,27 @@ impl<'backend> AinExecutor<'backend> {
);

if direction == TransferDirection::EvmIn {
let DST20BridgeInfo { address, storage } = bridge_dst20(
self.backend,
contract_address,
signed_tx.sender,
amount,
direction,
)?;
let DST20BridgeInfo { address, storage } =
bridge_dst20_in(self.backend, contract_address, amount)?;
self.update_storage(address, storage)?;
self.commit();
}

let allowance = dst20_allowance(direction, signed_tx.sender, amount);
self.update_storage(contract_address, allowance)?;
self.commit();

let (tx_response, receipt) = self.exec(&signed_tx, U256::MAX, U256::zero());
if !tx_response.exit_reason.is_succeed() {
debug!(
"[apply_queue_tx] DST20 bridge failed VM execution {:?}, data {}",
tx_response.exit_reason,
hex::encode(&tx_response.data)
);
return Err(format_err!(
"[apply_queue_tx] DST20 bridge failed VM execution {:?}",
tx_response.exit_reason
"[apply_queue_tx] DST20 bridge failed VM execution {:?}, data {:?}",
tx_response.exit_reason,
tx_response.data
)
.into());
}
Expand All @@ -370,13 +375,8 @@ impl<'backend> AinExecutor<'backend> {
);

if direction == TransferDirection::EvmOut {
let DST20BridgeInfo { address, storage } = bridge_dst20(
self.backend,
contract_address,
signed_tx.sender,
amount,
direction,
)?;
let DST20BridgeInfo { address, storage } =
bridge_dst20_out(self.backend, contract_address, amount)?;
self.update_storage(address, storage)?;
}

Expand Down
18 changes: 8 additions & 10 deletions lib/ain-rs-exports/src/evm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -112,14 +112,16 @@ pub fn evm_try_create_and_sign_transfer_domain_tx(
let FixedContract { fixed_address, .. } = get_transferdomain_contract();
let action = TransactionAction::Call(fixed_address);

let Ok(sender) = ctx.from.parse::<H160>() else {
return cross_boundary_error_return(result, format!("Invalid address {}", ctx.from));
};

let (from_address, to_address) = if ctx.direction {
let Ok(to_address) = ctx.to.parse() else {
return cross_boundary_error_return(result, format!("Invalid address {}", ctx.to));
};
let Ok(from_address) = ctx.from.parse::<H160>() else {
return cross_boundary_error_return(result, format!("Invalid address {}", ctx.from));
};
(from_address, to_address)
// Send EvmIn from contract address
(fixed_address, to_address)
} else {
let Ok(from_address) = ctx.from.parse() else {
return cross_boundary_error_return(result, format!("Invalid address {}", ctx.from));
Expand Down Expand Up @@ -236,14 +238,10 @@ pub fn evm_try_create_and_sign_transfer_domain_tx(
let nonce = if ctx.use_nonce {
U256::from(ctx.nonce)
} else {
let Ok(nonce) = SERVICES
.evm
.core
.get_next_account_nonce(from_address, state_root)
else {
let Ok(nonce) = SERVICES.evm.core.get_next_account_nonce(sender, state_root) else {
return cross_boundary_error_return(
result,
format!("Could not get nonce for {from_address:x?}"),
format!("Could not get nonce for {sender:x?}"),
);
};
nonce
Expand Down
Loading