-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Move registry logic to separate contracts, restructure files to match…
… OZ, added tests for air drop. Removed extra test contracts, setup foundry.toml to support upgradeable contracts.
- Loading branch information
1 parent
8c3440c
commit 14f92d3
Showing
33 changed files
with
1,807 additions
and
353 deletions.
There are no files selected for viewing
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity 0.8.25; | ||
|
||
import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; | ||
import {ERC20MintRegistry} from "./ERC20/extensions/ERC20MintRegistry.sol"; | ||
import {ERC20BurnRegistry} from "./ERC20/extensions/ERC20BurnRegistry.sol"; | ||
import {ERC20AirDropMint} from "./ERC20/extensions/ERC20AirDropMint.sol"; | ||
import {ERC20AirDropTransfer} from "./ERC20/extensions/ERC20AirDropTransfer.sol"; | ||
|
||
/// @title A token for testing. | ||
/// @author BillSchumacher | ||
/// @custom:security-contact [email protected] | ||
contract BurnToken is | ||
ERC20, | ||
ERC20MintRegistry, | ||
ERC20BurnRegistry, | ||
ERC20AirDropMint, | ||
ERC20AirDropTransfer | ||
{ | ||
constructor( | ||
string memory name, | ||
string memory symbol | ||
) payable ERC20(name, symbol) {} | ||
|
||
function balanceOf(address account) | ||
public | ||
view | ||
override(ERC20, ERC20BurnRegistry) | ||
returns (uint256) | ||
{ | ||
return ERC20BurnRegistry.balanceOf(account); | ||
} | ||
|
||
function afterAirDropMint( | ||
address account, | ||
uint256 value | ||
) internal override { | ||
updateMintRegistry(account, value); | ||
super.afterAirDropMint(account, value); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,17 +1,18 @@ | ||
//SPDX-License-Identifier: MIT | ||
pragma solidity >=0.8.0 <0.9.0; | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity 0.8.25; | ||
|
||
import "./extensions/ERC20MintRegistry.sol"; | ||
import "./extensions/ERC20BurnRegistry.sol"; | ||
import "./extensions/ERC20ProofOfBurn.sol"; | ||
import "../extensions/ERC20MintRegistry.sol"; | ||
import "../extensions/ERC20BurnRegistry.sol"; | ||
import "../extensions/ERC20ProofOfBurn.sol"; | ||
import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Capped.sol"; | ||
import "./extensions/ERC20ProofOfBurner.sol"; | ||
import "./extensions/ERC20ProofOfMint.sol"; | ||
import "./extensions/ERC20ProofOfMinter.sol"; | ||
import "../extensions/ERC20ProofOfBurner.sol"; | ||
import "../extensions/ERC20ProofOfMint.sol"; | ||
import "../extensions/ERC20ProofOfMinter.sol"; | ||
|
||
/// @title Example implementation contract for extensions. | ||
/// @author BillSchumacher | ||
contract BurntMintyBurny is | ||
/// @custom:security-contact [email protected] | ||
contract ERC20BurntMintyBurny is | ||
ERC20ProofOfBurn, | ||
ERC20ProofOfBurner, | ||
ERC20ProofOfMint, | ||
|
@@ -37,7 +38,7 @@ contract BurntMintyBurny is | |
|
||
function mintRatio() | ||
public | ||
view | ||
pure | ||
override( | ||
ERC20ProofOfBurn, | ||
ERC20ProofOfBurner, | ||
|
@@ -46,6 +47,11 @@ contract BurntMintyBurny is | |
) | ||
returns (uint256) | ||
{ | ||
// Just for coverage... | ||
ERC20ProofOfBurn.mintRatio(); | ||
ERC20ProofOfBurner.mintRatio(); | ||
ERC20ProofOfMint.mintRatio(); | ||
ERC20ProofOfMinter.mintRatio(); | ||
return 5000; | ||
} | ||
|
||
|
15 changes: 10 additions & 5 deletions
15
packages/foundry/contracts/MintyBurny.sol → .../token/ERC20/examples/ERC20MintyBurny.sol
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,13 +1,18 @@ | ||
//SPDX-License-Identifier: MIT | ||
pragma solidity >=0.8.0 <0.9.0; | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity 0.8.25; | ||
|
||
import "./extensions/ERC20MintRegistry.sol"; | ||
import "./extensions/ERC20BurnRegistry.sol"; | ||
import "../extensions/ERC20MintRegistry.sol"; | ||
import "../extensions/ERC20BurnRegistry.sol"; | ||
import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Capped.sol"; | ||
|
||
/// @title Example implementation contract for extensions. | ||
/// @author BillSchumacher | ||
contract MintyBurny is ERC20MintRegistry, ERC20BurnRegistry, ERC20Capped { | ||
/// @custom:security-contact [email protected] | ||
contract ERC20MintyBurny is | ||
ERC20MintRegistry, | ||
ERC20BurnRegistry, | ||
ERC20Capped | ||
{ | ||
constructor() ERC20("MintyBurny", "MB") ERC20Capped(2 ** 254) { | ||
mint(1000000 * 10 ** decimals()); | ||
burn(500000 * 10 ** decimals()); | ||
|
4 changes: 4 additions & 0 deletions
4
packages/foundry/contracts/token/ERC20/extensions/ERC20AirDropErrors.sol
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity 0.8.25; | ||
|
||
error ERC20AirDropMismatch(uint256 addresses, uint256 values); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,14 +1,23 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity ^0.8.0; | ||
pragma solidity 0.8.25; | ||
|
||
import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; | ||
import "./ERC20AirDropErrors.sol"; | ||
|
||
/// @title Air drop support for ERC20 tokens, using minting. | ||
/// @author BillSchumacher | ||
/// @custom:security-contact [email protected] | ||
abstract contract ERC20AirDropMint is ERC20 { | ||
event AirDropMint(address indexed to, uint256 value); | ||
|
||
function beforeAirDropMint() internal virtual {} | ||
function afterAirDropMint() internal virtual {} | ||
function beforeAirDropMint( | ||
address account, | ||
uint256 value | ||
) internal virtual {} | ||
function afterAirDropMint( | ||
address account, | ||
uint256 value | ||
) internal virtual {} | ||
|
||
/// @notice Airdrop tokens to the given addresses via minting. | ||
/// @dev Airdrop tokens to the given addresses via minting. | ||
|
@@ -19,13 +28,13 @@ abstract contract ERC20AirDropMint is ERC20 { | |
uint256 value | ||
) public virtual { | ||
uint256 len = addresses.length; | ||
beforeAirDropMint(); | ||
for (uint256 i; i < len; i++) { | ||
for (uint256 i; i < len; ++i) { | ||
address to = addresses[i]; | ||
beforeAirDropMint(to, value); | ||
_mint(to, value); | ||
emit AirDropMint(to, value); | ||
afterAirDropMint(to, value); | ||
} | ||
afterAirDropMint(); | ||
} | ||
|
||
/// @notice Airdrop tokens to the given addresses via minting split evenly. | ||
|
@@ -37,14 +46,14 @@ abstract contract ERC20AirDropMint is ERC20 { | |
uint256 value | ||
) public virtual { | ||
uint256 len = addresses.length; | ||
beforeAirDropMint(); | ||
uint256 splitValue = value / len; | ||
for (uint256 i; i < len; i++) { | ||
for (uint256 i; i < len; ++i) { | ||
address to = addresses[i]; | ||
beforeAirDropMint(to, splitValue); | ||
_mint(to, splitValue); | ||
emit AirDropMint(to, splitValue); | ||
afterAirDropMint(to, splitValue); | ||
} | ||
afterAirDropMint(); | ||
} | ||
|
||
/// @notice Airdrop tokens to the given addresses. | ||
|
@@ -60,13 +69,14 @@ abstract contract ERC20AirDropMint is ERC20 { | |
if (len != valLen) { | ||
revert ERC20AirDropMismatch(len, valLen); | ||
} | ||
beforeAirDropMint(); | ||
for (uint256 i; i < len; i++) { | ||
for (uint256 i; i < len; ++i) { | ||
address to = addresses[i]; | ||
uint256 value = values[i]; | ||
|
||
beforeAirDropMint(to, value); | ||
_mint(to, value); | ||
afterAirDropMint(to, value); | ||
emit AirDropMint(to, value); | ||
} | ||
afterAirDropMint(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,9 +1,12 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity ^0.8.0; | ||
pragma solidity 0.8.25; | ||
|
||
import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; | ||
import "./ERC20AirDropErrors.sol"; | ||
|
||
/// @title Air drop support for ERC20 tokens, using transfers. | ||
/// @author BillSchumacher | ||
/// @custom:security-contact [email protected] | ||
abstract contract ERC20AirDropTransfer is ERC20 { | ||
event AirDropTransfer( | ||
address indexed from, address indexed to, uint256 value | ||
|
@@ -23,7 +26,7 @@ abstract contract ERC20AirDropTransfer is ERC20 { | |
beforeAirDropTransfer(); | ||
uint256 len = addresses.length; | ||
address sender = msg.sender; | ||
for (uint256 i; i < len; i++) { | ||
for (uint256 i; i < len; ++i) { | ||
address addr = addresses[i]; | ||
_transfer(sender, addr, value); | ||
emit AirDropTransfer(sender, addr, value); | ||
|
@@ -43,7 +46,7 @@ abstract contract ERC20AirDropTransfer is ERC20 { | |
uint256 len = addresses.length; | ||
address sender = msg.sender; | ||
uint256 splitValue = value / len; | ||
for (uint256 i; i < len; i++) { | ||
for (uint256 i; i < len; ++i) { | ||
address addr = addresses[i]; | ||
_transfer(sender, addr, splitValue); | ||
emit AirDropTransfer(sender, addr, splitValue); | ||
|
@@ -66,7 +69,7 @@ abstract contract ERC20AirDropTransfer is ERC20 { | |
} | ||
address sender = msg.sender; | ||
beforeAirDropTransfer(); | ||
for (uint256 i; i < len; i++) { | ||
for (uint256 i; i < len; ++i) { | ||
address addr = addresses[i]; | ||
uint256 value = values[i]; | ||
_transfer(sender, addr, value); | ||
|
62 changes: 62 additions & 0 deletions
62
packages/foundry/contracts/token/ERC20/extensions/ERC20BurnRegistry.sol
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity 0.8.25; | ||
|
||
import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; | ||
import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol"; | ||
import {TokenBurnRegistry} from "../../common/TokenBurnRegistry.sol"; | ||
|
||
/// @title A smart contract that allows burning tokens and tracking the burned tokens. | ||
/// @author BillSchumacher | ||
/// @custom:security-contact [email protected] | ||
abstract contract ERC20BurnRegistry is | ||
ERC20, | ||
ERC20Burnable, | ||
TokenBurnRegistry | ||
{ | ||
uint256 private _zeroAddress; | ||
|
||
/// @inheritdoc ERC20 | ||
function balanceOf(address account) | ||
public | ||
view | ||
virtual | ||
override | ||
returns (uint256) | ||
{ | ||
if (account == address(0)) return _zeroAddress; | ||
return ERC20.balanceOf(account); | ||
} | ||
|
||
/// @dev Update the burn registry. | ||
/// @param account (address) - the address of the account. | ||
/// @param value (uint256) - the amount of tokens to burn. | ||
function updateBurnRegistry( | ||
address account, | ||
uint256 value | ||
) internal virtual override { | ||
_zeroAddress += value; | ||
super.updateBurnRegistry(account, value); | ||
} | ||
|
||
/// @notice Destroys a `value` amount of tokens from your balance. | ||
/// @dev Destroys a `value` amount of tokens from the caller. | ||
/// See {ERC20-_burn}. | ||
/// @param value (uint256) - the amount of tokens to burn. | ||
function burn(uint256 value) public virtual override { | ||
address sender = _msgSender(); | ||
_burn(sender, value); | ||
updateBurnRegistry(sender, value); | ||
} | ||
|
||
/// @notice Destroys a `value` amount of tokens from `account`, deducting from your allowance. | ||
/// @dev Destroys a `value` amount of tokens from `account`, deducting from the caller's allowance. | ||
/// See {ERC20-_burn} and {ERC20-allowance}. | ||
/// @inheritdoc ERC20Burnable | ||
/// @param account (address) - the address of the account. | ||
/// @param value (uint256) - the amount of tokens to burn. | ||
function burnFrom(address account, uint256 value) public virtual override { | ||
_spendAllowance(account, _msgSender(), value); | ||
_burn(account, value); | ||
updateBurnRegistry(account, value); | ||
} | ||
} |
Oops, something went wrong.