Skip to content

Commit

Permalink
clarify denom definition and remove unnecessary validation for denom
Browse files Browse the repository at this point in the history
Signed-off-by: Jun Kimura <[email protected]>
  • Loading branch information
bluele committed Oct 9, 2023
1 parent 201e8f5 commit 33ab9ff
Show file tree
Hide file tree
Showing 4 changed files with 93 additions and 31 deletions.
51 changes: 27 additions & 24 deletions contracts/apps/20-transfer/ICS20Bank.sol
Original file line number Diff line number Diff line change
Expand Up @@ -26,56 +26,59 @@ contract ICS20Bank is Context, AccessControl, IICS20Bank {
_setupRole(OPERATOR_ROLE, operator);
}

function balanceOf(address account, string calldata id) external view virtual returns (uint256) {
function balanceOf(address account, string calldata denom) external view virtual returns (uint256) {
require(account != address(0), "ICS20Bank: balance query for the zero address");
return _balances[id][account];
return _balances[denom][account];
}

function transferFrom(address from, address to, string calldata id, uint256 amount) external virtual override {
function transferFrom(address from, address to, string calldata denom, uint256 amount) external virtual override {
require(to != address(0), "ICS20Bank: transfer to the zero address");
require(
from == _msgSender() || hasRole(OPERATOR_ROLE, _msgSender()), "ICS20Bank: caller is not owner nor approved"
);

uint256 fromBalance = _balances[id][from];
uint256 fromBalance = _balances[denom][from];
require(fromBalance >= amount, "ICS20Bank: insufficient balance for transfer");
_balances[id][from] = fromBalance - amount;
_balances[id][to] += amount;
unchecked {
_balances[denom][from] = fromBalance - amount;
}
_balances[denom][to] += amount;
}

function mint(address account, string calldata id, uint256 amount) external virtual override {
function mint(address account, string calldata denom, uint256 amount) external virtual override {
require(hasRole(OPERATOR_ROLE, _msgSender()), "ICS20Bank: must have minter role to mint");
_mint(account, id, amount);
_mint(account, denom, amount);
}

function burn(address account, string calldata id, uint256 amount) external virtual override {
function burn(address account, string calldata denom, uint256 amount) external virtual override {
require(hasRole(OPERATOR_ROLE, _msgSender()), "ICS20Bank: must have minter role to mint");
_burn(account, id, amount);
_burn(account, denom, amount);
}

function addressToDenom(address tokenContract) public pure virtual override returns (string memory) {
return Strings.toHexString(tokenContract);
}

function deposit(address tokenContract, uint256 amount, address receiver) external virtual {
function deposit(address tokenContract, uint256 amount, address receiver) external virtual override {
require(tokenContract.isContract());
require(IERC20(tokenContract).transferFrom(_msgSender(), address(this), amount));
_mint(receiver, _genDenom(tokenContract), amount);
_mint(receiver, addressToDenom(tokenContract), amount);
}

function withdraw(address tokenContract, uint256 amount, address receiver) external virtual {
function withdraw(address tokenContract, uint256 amount, address receiver) external virtual override {
require(tokenContract.isContract());
_burn(_msgSender(), _genDenom(tokenContract), amount);
_burn(_msgSender(), addressToDenom(tokenContract), amount);
require(IERC20(tokenContract).transfer(receiver, amount));
}

function _mint(address account, string memory id, uint256 amount) internal virtual {
_balances[id][account] += amount;
function _mint(address account, string memory denom, uint256 amount) internal virtual {
_balances[denom][account] += amount;
}

function _burn(address account, string memory id, uint256 amount) internal virtual {
uint256 accountBalance = _balances[id][account];
function _burn(address account, string memory denom, uint256 amount) internal virtual {
uint256 accountBalance = _balances[denom][account];
require(accountBalance >= amount, "ICS20Bank: burn amount exceeds balance");
_balances[id][account] = accountBalance - amount;
}

function _genDenom(address tokenContract) internal pure virtual returns (string memory) {
return Strings.toHexString(tokenContract);
unchecked {
_balances[denom][account] = accountBalance - amount;
}
}
}
6 changes: 3 additions & 3 deletions contracts/apps/20-transfer/ICS20Transfer.sol
Original file line number Diff line number Diff line change
Expand Up @@ -38,15 +38,15 @@ abstract contract ICS20Transfer is IBCAppBase {
);
} else {
// sender chain is the source, mint vouchers

// ensure denom is not required to be escaped
if (ICS20Lib.isEscapeNeededString(denom)) {
success = false;
} else {
success = _mint(
receiver,
string(
abi.encodePacked(
_getDenomPrefix(packet.destination_port, packet.destination_channel), data.denom
)
abi.encodePacked(_getDenomPrefix(packet.destination_port, packet.destination_channel), denom)
),
data.amount
);
Expand Down
11 changes: 10 additions & 1 deletion contracts/apps/20-transfer/ICS20TransferBank.sol
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,15 @@ contract ICS20TransferBank is ICS20Transfer {
bank = bank_;
}

/**
* @dev sendTransfer sends a transfer packet to the destination chain.
* @param denom denomination of the token. It can assume the denom string is escaped or not required to be escaped.
* @param amount amount of the token
* @param receiver receiver address on the destination chain
* @param sourcePort source port of the packet
* @param sourceChannel source channel of the packet
* @param timeoutHeight timeout height of the packet
*/
function sendTransfer(
string calldata denom,
uint256 amount,
Expand All @@ -25,7 +34,7 @@ contract ICS20TransferBank is ICS20Transfer {
string calldata sourceChannel,
uint64 timeoutHeight
) external {
require(ICS20Lib.isEscapedJSONString(denom) && ICS20Lib.isEscapedJSONString(receiver), "unescaped string");
require(ICS20Lib.isEscapedJSONString(receiver), "unescaped receiver");
bytes memory denomPrefix = _getDenomPrefix(sourcePort, sourceChannel);
if (!bytes(denom).slice(0, denomPrefix.length).equal(denomPrefix)) {
// sender is source chain
Expand Down
56 changes: 53 additions & 3 deletions contracts/apps/20-transfer/IICS20Bank.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,57 @@
pragma solidity ^0.8.9;

interface IICS20Bank {
function transferFrom(address from, address to, string calldata id, uint256 amount) external;
function mint(address account, string calldata id, uint256 amount) external;
function burn(address account, string calldata id, uint256 amount) external;
/**
* @dev balanceOf returns the balance of the account.
* @param account account address
* @param denom denom of the token
*/
function balanceOf(address account, string calldata denom) external view returns (uint256);

/**
* @dev transferFrom transfers tokens from the sender to the receiver.
* @param from sender address
* @param to receiver address
* @param denom denom of the token
* @param amount amount of the token
*/
function transferFrom(address from, address to, string calldata denom, uint256 amount) external;

/**
* @dev mint mints tokens to the account.
* @param account account address
* @param denom denom of the token
* @param amount amount of the token
*/
function mint(address account, string calldata denom, uint256 amount) external;

/**
* @dev burn burns tokens from the account.
* @param account account address
* @param denom denom of the token
* @param amount amount of the token
*/
function burn(address account, string calldata denom, uint256 amount) external;

/**
* @dev addressToDenom returns the denom of the token corresponding to the contract address.
* The denom must be a json escaped string.
*/
function addressToDenom(address tokenContract) external pure returns (string memory);

/**
* @dev deposit deposits tokens to the bank.
* @param tokenContract token contract address
* @param amount amount of the token
* @param receiver receiver address on the bank
*/
function deposit(address tokenContract, uint256 amount, address receiver) external;

/**
* @dev withdraw withdraws tokens from the bank.
* @param tokenContract token contract address
* @param amount amount of the token
* @param receiver receiver address on the bank
*/
function withdraw(address tokenContract, uint256 amount, address receiver) external;
}

0 comments on commit 33ab9ff

Please sign in to comment.