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

Change units to be an overridable function #54

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
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
31 changes: 18 additions & 13 deletions contracts/ERC404.sol
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,6 @@ abstract contract ERC404 is IERC404 {
/// @dev Decimals for ERC-20 representation
uint8 public immutable decimals;

/// @dev Units for ERC-20 representation
uint256 public immutable units;

/// @dev Total supply in ERC-20 representation
uint256 public totalSupply;

Expand Down Expand Up @@ -81,13 +78,21 @@ abstract contract ERC404 is IERC404 {
}

decimals = decimals_;
units = 10 ** decimals;

// EIP-2612 initialization
_INITIAL_CHAIN_ID = block.chainid;
_INITIAL_DOMAIN_SEPARATOR = _computeDomainSeparator();
}

/*«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-*/
/* BASE UNIT FUNCTION TO OVERRIDE */
/*-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»*/

/// @dev Amount of token balance that is equal to one NFT.
function _unit() internal view virtual returns (uint256) {
return 10 ** decimals;
}

/// @notice Function to find owner of a given ERC-721 token
function ownerOf(
uint256 id_
Expand Down Expand Up @@ -271,7 +276,7 @@ abstract contract ERC404 is IERC404 {

// Transfer 1 * units ERC-20 and 1 ERC-721 token.
// ERC-721 transfer exemptions handled above. Can't make it to this point if either is transfer exempt.
_transferERC20(from_, to_, units);
_transferERC20(from_, to_, _unit());
_transferERC721(from_, to_, id_);
}

Expand Down Expand Up @@ -563,8 +568,8 @@ abstract contract ERC404 is IERC404 {
// to transfer ERC-721s from the sender, but the recipient should receive ERC-721s
// from the bank/minted for any whole number increase in their balance.
// Only cares about whole number increments.
uint256 tokensToRetrieveOrMint = (balanceOf[to_] / units) -
(erc20BalanceOfReceiverBefore / units);
uint256 tokensToRetrieveOrMint = (balanceOf[to_] / _unit()) -
(erc20BalanceOfReceiverBefore / _unit());
for (uint256 i = 0; i < tokensToRetrieveOrMint; ) {
_retrieveOrMintERC721(to_);
unchecked {
Expand All @@ -576,8 +581,8 @@ abstract contract ERC404 is IERC404 {
// to withdraw and store ERC-721s from the sender, but the recipient should not
// receive ERC-721s from the bank/minted.
// Only cares about whole number increments.
uint256 tokensToWithdrawAndStore = (erc20BalanceOfSenderBefore / units) -
(balanceOf[from_] / units);
uint256 tokensToWithdrawAndStore = (erc20BalanceOfSenderBefore /
_unit()) - (balanceOf[from_] / _unit());
for (uint256 i = 0; i < tokensToWithdrawAndStore; ) {
_withdrawAndStoreERC721(from_);
unchecked {
Expand All @@ -595,7 +600,7 @@ abstract contract ERC404 is IERC404 {
// due to receiving a fractional part that completes a whole token, retrieve or mint an NFT to the recevier.

// Whole tokens worth of ERC-20s get transferred as ERC-721s without any burning/minting.
uint256 nftsToTransfer = value_ / units;
uint256 nftsToTransfer = value_ / _unit();
for (uint256 i = 0; i < nftsToTransfer; ) {
// Pop from sender's ERC-721 stack and transfer them (LIFO)
uint256 indexOfLastToken = _owned[from_].length - 1;
Expand All @@ -619,7 +624,7 @@ abstract contract ERC404 is IERC404 {
// If this is a self-send and the before and after balances are equal (not always the case but often),
// then no ERC-721s will be lost here.
if (
erc20BalanceOfSenderBefore / units - erc20BalanceOf(from_) / units >
erc20BalanceOfSenderBefore / _unit() - erc20BalanceOf(from_) / _unit() >
nftsToTransfer
) {
_withdrawAndStoreERC721(from_);
Expand All @@ -634,7 +639,7 @@ abstract contract ERC404 is IERC404 {
// an additional ERC-721 gained due to the fractional portion of the transfer.
// Again, for self-sends where the before and after balances are equal, no ERC-721s will be gained here.
if (
erc20BalanceOf(to_) / units - erc20BalanceOfReceiverBefore / units >
erc20BalanceOf(to_) / _unit() - erc20BalanceOfReceiverBefore / _unit() >
nftsToTransfer
) {
_retrieveOrMintERC721(to_);
Expand Down Expand Up @@ -744,7 +749,7 @@ abstract contract ERC404 is IERC404 {

/// @notice Function to reinstate balance on exemption removal
function _reinstateERC721Balance(address target_) private {
uint256 expectedERC721Balance = erc20BalanceOf(target_) / units;
uint256 expectedERC721Balance = erc20BalanceOf(target_) / _unit();
uint256 actualERC721Balance = erc721BalanceOf(target_);

for (uint256 i = 0; i < expectedERC721Balance - actualERC721Balance; ) {
Expand Down
31 changes: 18 additions & 13 deletions contracts/ERC404U16.sol
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,6 @@ abstract contract ERC404U16 is IERC404 {
/// @dev Decimals for ERC-20 representation
uint8 public immutable decimals;

/// @dev Units for ERC-20 representation
uint256 public immutable units;

/// @dev Total supply in ERC-20 representation
uint256 public totalSupply;

Expand Down Expand Up @@ -83,13 +80,21 @@ abstract contract ERC404U16 is IERC404 {
}

decimals = decimals_;
units = 10 ** decimals;

// EIP-2612 initialization
_INITIAL_CHAIN_ID = block.chainid;
_INITIAL_DOMAIN_SEPARATOR = _computeDomainSeparator();
}

/*«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-*/
/* BASE UNIT FUNCTION TO OVERRIDE */
/*-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»*/

/// @dev Amount of token balance that is equal to one NFT.
function _unit() internal view virtual returns (uint256) {
return 10 ** decimals;
}

/// @notice Function to find owner of a given ERC-721 token
function ownerOf(
uint256 id_
Expand Down Expand Up @@ -282,7 +287,7 @@ abstract contract ERC404U16 is IERC404 {

// Transfer 1 * units ERC-20 and 1 ERC-721 token.
// ERC-721 transfer exemptions handled above. Can't make it to this point if either is transfer exempt.
_transferERC20(from_, to_, units);
_transferERC20(from_, to_, _unit());
_transferERC721(from_, to_, id_);
}

Expand Down Expand Up @@ -574,8 +579,8 @@ abstract contract ERC404U16 is IERC404 {
// to transfer ERC-721s from the sender, but the recipient should receive ERC-721s
// from the bank/minted for any whole number increase in their balance.
// Only cares about whole number increments.
uint256 tokensToRetrieveOrMint = (balanceOf[to_] / units) -
(erc20BalanceOfReceiverBefore / units);
uint256 tokensToRetrieveOrMint = (balanceOf[to_] / _unit()) -
(erc20BalanceOfReceiverBefore / _unit());
for (uint256 i = 0; i < tokensToRetrieveOrMint; ) {
_retrieveOrMintERC721(to_);
unchecked {
Expand All @@ -587,8 +592,8 @@ abstract contract ERC404U16 is IERC404 {
// to withdraw and store ERC-721s from the sender, but the recipient should not
// receive ERC-721s from the bank/minted.
// Only cares about whole number increments.
uint256 tokensToWithdrawAndStore = (erc20BalanceOfSenderBefore / units) -
(balanceOf[from_] / units);
uint256 tokensToWithdrawAndStore = (erc20BalanceOfSenderBefore /
_unit()) - (balanceOf[from_] / _unit());
for (uint256 i = 0; i < tokensToWithdrawAndStore; ) {
_withdrawAndStoreERC721(from_);
unchecked {
Expand All @@ -606,7 +611,7 @@ abstract contract ERC404U16 is IERC404 {
// due to receiving a fractional part that completes a whole token, retrieve or mint an NFT to the recevier.

// Whole tokens worth of ERC-20s get transferred as ERC-721s without any burning/minting.
uint256 nftsToTransfer = value_ / units;
uint256 nftsToTransfer = value_ / _unit();
for (uint256 i = 0; i < nftsToTransfer; ) {
// Pop from sender's ERC-721 stack and transfer them (LIFO)
uint256 indexOfLastToken = _owned[from_].length - 1;
Expand All @@ -623,14 +628,14 @@ abstract contract ERC404U16 is IERC404 {
// Check if the send causes the sender to lose a whole token that was represented by an ERC-721
// due to a fractional part being transferred.
if (
erc20BalanceOfSenderBefore / units - erc20BalanceOf(from_) / units >
erc20BalanceOfSenderBefore / _unit() - erc20BalanceOf(from_) / _unit() >
nftsToTransfer
) {
_withdrawAndStoreERC721(from_);
}

if (
erc20BalanceOf(to_) / units - erc20BalanceOfReceiverBefore / units >
erc20BalanceOf(to_) / _unit() - erc20BalanceOfReceiverBefore / _unit() >
nftsToTransfer
) {
_retrieveOrMintERC721(to_);
Expand Down Expand Up @@ -740,7 +745,7 @@ abstract contract ERC404U16 is IERC404 {

/// @notice Function to reinstate balance on exemption removal
function _reinstateERC721Balance(address target_) private {
uint256 expectedERC721Balance = erc20BalanceOf(target_) / units;
uint256 expectedERC721Balance = erc20BalanceOf(target_) / _unit();
uint256 actualERC721Balance = erc721BalanceOf(target_);

for (uint256 i = 0; i < expectedERC721Balance - actualERC721Balance; ) {
Expand Down
2 changes: 1 addition & 1 deletion contracts/examples/ERC404Example.sol
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ contract ERC404Example is Ownable, ERC404 {
) ERC404(name_, symbol_, decimals_) Ownable(initialOwner_) {
// Do not mint the ERC721s to the initial owner, as it's a waste of gas.
_setERC721TransferExempt(initialMintRecipient_, true);
_mintERC20(initialMintRecipient_, maxTotalSupplyERC721_ * units);
_mintERC20(initialMintRecipient_, maxTotalSupplyERC721_ * _unit());
}

function tokenURI(uint256 id_) public pure override returns (string memory) {
Expand Down
2 changes: 1 addition & 1 deletion contracts/examples/ERC404ExampleU16.sol
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ contract ERC404ExampleU16 is Ownable, ERC404U16 {
) ERC404U16(name_, symbol_, decimals_) Ownable(initialOwner_) {
// Do not mint the ERC721s to the initial owner, as it's a waste of gas.
_setERC721TransferExempt(initialMintRecipient_, true);
_mintERC20(initialMintRecipient_, maxTotalSupplyERC721_ * units);
_mintERC20(initialMintRecipient_, maxTotalSupplyERC721_ * _unit());
}

function tokenURI(uint256 id_) public pure override returns (string memory) {
Expand Down
2 changes: 1 addition & 1 deletion contracts/examples/ERC404ExampleUniswapV2.sol
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ contract ERC404ExampleUniswapV2 is Ownable, ERC404, ERC404UniswapV2Exempt {
{
// Do not mint the ERC721s to the initial owner, as it's a waste of gas.
_setERC721TransferExempt(initialMintRecipient_, true);
_mintERC20(initialMintRecipient_, maxTotalSupplyERC721_ * units);
_mintERC20(initialMintRecipient_, maxTotalSupplyERC721_ * _unit());
}

function tokenURI(uint256 id_) public pure override returns (string memory) {
Expand Down
2 changes: 1 addition & 1 deletion contracts/examples/ERC404ExampleUniswapV3.sol
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ contract ERC404ExampleUniswapV3 is Ownable, ERC404, ERC404UniswapV3Exempt {
{
// Do not mint the ERC721s to the initial owner, as it's a waste of gas.
_setERC721TransferExempt(initialMintRecipient_, true);
_mintERC20(initialMintRecipient_, maxTotalSupplyERC721_ * units);
_mintERC20(initialMintRecipient_, maxTotalSupplyERC721_ * _unit());
}

function tokenURI(uint256 id_) public pure override returns (string memory) {
Expand Down