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

Major bump to comment lines ratio #73

Merged
72 changes: 36 additions & 36 deletions .gas-snapshot
Original file line number Diff line number Diff line change
Expand Up @@ -2,48 +2,48 @@ BridgedERC20Test:testBurn() (gas: 120710)
BridgedERC20Test:testBurnUnauthorizedReverts() (gas: 149477)
BridgedERC20Test:testMint() (gas: 85270)
BridgedERC20Test:testMintUnauthorizedReverts() (gas: 70722)
BridgedERC20Test:testSetDisclosures(string) (runs: 518, μ: 61182, ~: 68688)
BridgedERC20Test:testSetName(string) (runs: 518, μ: 60148, ~: 68654)
BridgedERC20Test:testSetRestrictor(address) (runs: 518, μ: 19502, ~: 19508)
BridgedERC20Test:testSetSymbol(string) (runs: 518, μ: 61557, ~: 68720)
BridgedERC20Test:testSetDisclosures(string) (runs: 518, μ: 60664, ~: 68688)
BridgedERC20Test:testSetName(string) (runs: 518, μ: 60972, ~: 68654)
BridgedERC20Test:testSetRestrictor(address) (runs: 518, μ: 19508, ~: 19508)
BridgedERC20Test:testSetSymbol(string) (runs: 518, μ: 60445, ~: 68720)
BridgedERC20Test:testTransfer() (gas: 102095)
BridgedERC20Test:testTransferRestrictedFromReverts() (gas: 121429)
BridgedERC20Test:testTransferRestrictedToReverts() (gas: 123593)
BuyOrderIssuerTest:testCancelOrder(uint128,uint128,string) (runs: 518, μ: 370916, ~: 378792)
BuyOrderIssuerTest:testCancelOrderNotFoundReverts() (gas: 54694)
BuyOrderIssuerTest:testFillOrder(uint128,uint128,uint256) (runs: 518, μ: 338614, ~: 382418)
BuyOrderIssuerTest:testFillorderNoOrderReverts() (gas: 54549)
BuyOrderIssuerTest:testFulfillOrder(uint128,uint256) (runs: 518, μ: 342504, ~: 344288)
BuyOrderIssuerTest:testGetInputValue(uint64,uint64,uint128) (runs: 518, μ: 628977, ~: 632845)
BuyOrderIssuerTest:testInitialize(address,address) (runs: 518, μ: 7013243, ~: 7013243)
BuyOrderIssuerTest:testInitializeZeroOwnerReverts() (gas: 3449093)
BuyOrderIssuerTest:testInitializeZeroTreasuryReverts() (gas: 3523035)
BuyOrderIssuerTest:testNoFees(uint128) (runs: 518, μ: 20350, ~: 20350)
BuyOrderIssuerTest:testRequestCancel() (gas: 261898)
BuyOrderIssuerTest:testCancelOrder(uint128,uint128,string) (runs: 518, μ: 362197, ~: 369592)
BuyOrderIssuerTest:testCancelOrderNotFoundReverts() (gas: 37594)
BuyOrderIssuerTest:testFillOrder(uint128,uint128,uint256) (runs: 518, μ: 319851, ~: 362518)
BuyOrderIssuerTest:testFillorderNoOrderReverts() (gas: 37449)
BuyOrderIssuerTest:testFulfillOrder(uint128,uint256) (runs: 518, μ: 331186, ~: 332850)
BuyOrderIssuerTest:testGetInputValue(uint64,uint64,uint128) (runs: 518, μ: 629051, ~: 632930)
BuyOrderIssuerTest:testInitialize(address,address) (runs: 518, μ: 7081363, ~: 7081363)
BuyOrderIssuerTest:testInitializeZeroOwnerReverts() (gas: 3472134)
BuyOrderIssuerTest:testInitializeZeroTreasuryReverts() (gas: 3471791)
BuyOrderIssuerTest:testNoFees(uint128) (runs: 518, μ: 20435, ~: 20435)
BuyOrderIssuerTest:testRequestCancel() (gas: 241998)
BuyOrderIssuerTest:testRequestCancelNotFoundReverts() (gas: 27787)
BuyOrderIssuerTest:testRequestCancelNotRequesterReverts() (gas: 255440)
BuyOrderIssuerTest:testRequestOrder(uint128) (runs: 518, μ: 208947, ~: 272336)
BuyOrderIssuerTest:testRequestOrderCollisionReverts() (gas: 257327)
BuyOrderIssuerTest:testRequestOrderPausedReverts() (gas: 56734)
BuyOrderIssuerTest:testRequestOrderUnsupportedAssetReverts(address) (runs: 518, μ: 113169, ~: 113169)
BuyOrderIssuerTest:testRequestOrderUnsupportedPaymentReverts(address) (runs: 518, μ: 115636, ~: 115636)
BuyOrderIssuerTest:testRequestOrderWithPermit() (gas: 333250)
BuyOrderIssuerTest:testRequestOrderWithPermitCollisionReverts() (gas: 299841)
BuyOrderIssuerTest:testSetFees(address) (runs: 518, μ: 24723, ~: 24723)
BuyOrderIssuerTest:testRequestCancelNotRequesterReverts() (gas: 235540)
BuyOrderIssuerTest:testRequestOrder(uint128) (runs: 518, μ: 194228, ~: 252436)
BuyOrderIssuerTest:testRequestOrderCollisionReverts() (gas: 240227)
BuyOrderIssuerTest:testRequestOrderPausedReverts() (gas: 39634)
BuyOrderIssuerTest:testRequestOrderUnsupportedAssetReverts(address) (runs: 518, μ: 96069, ~: 96069)
BuyOrderIssuerTest:testRequestOrderUnsupportedPaymentReverts(address) (runs: 518, μ: 98536, ~: 98536)
BuyOrderIssuerTest:testRequestOrderWithPermit() (gas: 313350)
BuyOrderIssuerTest:testRequestOrderWithPermitCollisionReverts() (gas: 282741)
BuyOrderIssuerTest:testSetFees(address) (runs: 518, μ: 24903, ~: 24903)
BuyOrderIssuerTest:testSetOrdersPaused(bool) (runs: 518, μ: 22686, ~: 21789)
BuyOrderIssuerTest:testSetTreasury(address) (runs: 518, μ: 25267, ~: 25267)
BuyOrderIssuerTest:testSetTreasuryZeroReverts() (gas: 15982)
DirectBuyIssuerTest:testCancelOrder(uint128,uint128,string) (runs: 518, μ: 389509, ~: 397094)
DirectBuyIssuerTest:testCancelOrderUnreturnedEscrowReverts(uint128,uint128) (runs: 518, μ: 323685, ~: 323685)
DirectBuyIssuerTest:testFillOrder(uint128,uint128,uint128,uint256) (runs: 518, μ: 356933, ~: 343592)
DirectBuyIssuerTest:testReturnEscrow(uint128,uint256) (runs: 518, μ: 329431, ~: 324973)
DirectBuyIssuerTest:testTakeEscrow(uint128,uint256) (runs: 518, μ: 301280, ~: 286699)
DirectBuyIssuerTest:testCancelOrder(uint128,uint128,string) (runs: 518, μ: 379720, ~: 387890)
DirectBuyIssuerTest:testCancelOrderUnreturnedEscrowReverts(uint128,uint128) (runs: 518, μ: 306585, ~: 306585)
DirectBuyIssuerTest:testFillOrder(uint128,uint128,uint128,uint256) (runs: 518, μ: 337215, ~: 326489)
DirectBuyIssuerTest:testReturnEscrow(uint128,uint256) (runs: 518, μ: 309278, ~: 305073)
DirectBuyIssuerTest:testTakeEscrow(uint128,uint256) (runs: 518, μ: 281830, ~: 266799)
OrderFeesTest:testRecoverInputValueFromRemaining(uint64,uint128) (runs: 518, μ: 22551, ~: 22896)
OrderFeesTest:testSetFee(uint64,uint64,uint8,uint128) (runs: 518, μ: 589862, ~: 726435)
OrderFeesTest:testSetFee(uint64,uint64,uint8,uint128) (runs: 518, μ: 592375, ~: 726435)
OrderFeesTest:testUSDC() (gas: 15635)
SellOrderProcessorTest:testCancelOrder(uint128,uint128,uint128,string) (runs: 518, μ: 399734, ~: 423048)
SellOrderProcessorTest:testFillOrder(uint128,uint128,uint256) (runs: 518, μ: 339591, ~: 325645)
SellOrderProcessorTest:testFulfillOrder(uint128,uint256) (runs: 518, μ: 372815, ~: 385584)
SellOrderProcessorTest:testNoFees(uint128) (runs: 518, μ: 19436, ~: 19436)
SellOrderProcessorTest:testRequestOrder(uint128) (runs: 518, μ: 253696, ~: 259604)
TransferRestrictorTest:testRestrictUnrestrict(address) (runs: 518, μ: 36984, ~: 36977)
SellOrderProcessorTest:testCancelOrder(uint128,uint128,uint128,string) (runs: 518, μ: 391551, ~: 413855)
SellOrderProcessorTest:testFillOrder(uint128,uint128,uint256) (runs: 518, μ: 322047, ~: 308545)
SellOrderProcessorTest:testFulfillOrder(uint128,uint256) (runs: 518, μ: 361425, ~: 374145)
SellOrderProcessorTest:testNoFees(uint128) (runs: 518, μ: 19521, ~: 19521)
SellOrderProcessorTest:testRequestOrder(uint128) (runs: 518, μ: 233882, ~: 239704)
TransferRestrictorTest:testRestrictUnrestrict(address) (runs: 518, μ: 36985, ~: 36977)
51 changes: 44 additions & 7 deletions src/BridgedERC20.sol
Original file line number Diff line number Diff line change
@@ -1,31 +1,48 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;

// solady ERC20 allows EIP-2612 domain separator with `name` changes
import {ERC20} from "solady/tokens/ERC20.sol";
import {AccessControlDefaultAdminRules} from
"openzeppelin-contracts/contracts/access/AccessControlDefaultAdminRules.sol";
import {ITransferRestrictor} from "./ITransferRestrictor.sol";

/// @notice ERC20 with minter and blacklist.
/// @notice Core token contract for bridged assets.
/// @author Dinari (https://github.com/dinaricrypto/issuer-contracts/blob/main/src/BridgedERC20.sol)
/// ERC20 with minter, burner, and blacklist
/// Uses solady ERC20 which allows EIP-2612 domain separator with `name` changes
contract BridgedERC20 is ERC20, AccessControlDefaultAdminRules {
/// ------------------ Events ------------------ ///

/// @dev Emitted when `name` is set
event NameSet(string name);
/// @dev Emitted when `symbol` is set
event SymbolSet(string symbol);
/// @dev Emitted when `disclosures` URI is set
event DisclosuresSet(string disclosures);
/// @dev Emitted when transfer restrictor contract is set
event TransferRestrictorSet(ITransferRestrictor indexed transferRestrictor);

/// ------------------ Constants ------------------ ///

/// @notice Role for approved minters
bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE");
/// @notice Role for approved burners
bytes32 public constant BURNER_ROLE = keccak256("BURNER_ROLE");

string internal _name;
string internal _symbol;
/// ------------------ State ------------------ ///

/// @dev URI to disclosure information
/// @dev Token name
string private _name;
/// @dev Token symbol
string private _symbol;

/// @notice URI to disclosure information
string public disclosures;
/// @dev Contract to restrict transfers
/// @notice Contract to restrict transfers
ITransferRestrictor public transferRestrictor;

/// ------------------ Initialization ------------------ ///

constructor(
address owner,
string memory name_,
Expand All @@ -39,34 +56,50 @@ contract BridgedERC20 is ERC20, AccessControlDefaultAdminRules {
transferRestrictor = transferRestrictor_;
}

/// ------------------ Getters ------------------ ///

/// @notice Returns the name of the token
function name() public view virtual override returns (string memory) {
return _name;
}

/// @notice Returns the symbol of the token
function symbol() public view virtual override returns (string memory) {
return _symbol;
}

/// ------------------ Setters ------------------ ///

/// @notice Set token name
/// @dev Only callable by owner
function setName(string calldata name_) external onlyRole(DEFAULT_ADMIN_ROLE) {
_name = name_;
emit NameSet(name_);
}

/// @notice Set token symbol
/// @dev Only callable by owner
function setSymbol(string calldata symbol_) external onlyRole(DEFAULT_ADMIN_ROLE) {
_symbol = symbol_;
emit SymbolSet(symbol_);
}

/// @notice Set disclosures URI
/// @dev Only callable by owner
function setDisclosures(string calldata disclosures_) external onlyRole(DEFAULT_ADMIN_ROLE) {
disclosures = disclosures_;
emit DisclosuresSet(disclosures_);
}

/// @notice Set transfer restrictor contract
/// @dev Only callable by owner
function setTransferRestrictor(ITransferRestrictor restrictor) external onlyRole(DEFAULT_ADMIN_ROLE) {
transferRestrictor = restrictor;
emit TransferRestrictorSet(restrictor);
}

/// ------------------ Minting and Burning ------------------ ///

/// @notice Mint tokens
/// @param to Address to mint tokens to
/// @param value Amount of tokens to mint
Expand All @@ -82,12 +115,16 @@ contract BridgedERC20 is ERC20, AccessControlDefaultAdminRules {
_burn(msg.sender, value);
}

/// ------------------ Transfers ------------------ ///

/// @inheritdoc ERC20
function _beforeTokenTransfer(address from, address to, uint256) internal virtual override {
// restrictions ignored for minting and burning
// Restrictions ignored for minting and burning
if (from == address(0) || to == address(0) || address(transferRestrictor) == address(0)) {
return;
}

// Check transfer restrictions
transferRestrictor.requireNotRestricted(from, to);
}
}
8 changes: 7 additions & 1 deletion src/IMintBurn.sol
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;

/// @notice
/// @notice Interface for token minting and burning
/// @author Dinari (https://github.com/dinaricrypto/issuer-contracts/blob/main/src/IMintBurn.sol)
/// Implemented by BridgedERC20
interface IMintBurn {
/// @notice Mint new tokens
/// @param to Address to mint tokens to
/// @param value Amount of tokens to mint
function mint(address to, uint256 value) external;

/// @notice Burn tokens
/// @param value Amount of tokens to burn
function burn(uint256 value) external;
}
2 changes: 1 addition & 1 deletion src/ITransferRestrictor.sol
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;

/// @notice
/// @notice Interface for transfer restriction contract
/// @author Dinari (https://github.com/dinaricrypto/issuer-contracts/blob/main/src/ITransferRestrictor.sol)
interface ITransferRestrictor {
/// @notice Checks if the transfer is allowed
Expand Down
28 changes: 20 additions & 8 deletions src/TransferRestrictor.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,42 +2,54 @@
pragma solidity ^0.8.19;

import {Ownable2Step} from "openzeppelin-contracts/contracts/access/Ownable2Step.sol";
import "./ITransferRestrictor.sol";
import {ITransferRestrictor} from "./ITransferRestrictor.sol";

/// @notice Enforces transfer restrictions
/// @author Dinari (https://github.com/dinaricrypto/issuer-contracts/blob/main/src/TransferRestrictor.sol)
/// Maintains a single `owner` who can add or remove accounts from `blacklist`
contract TransferRestrictor is Ownable2Step, ITransferRestrictor {
/// ------------------ Types ------------------ ///

/// @dev Account is restricted
error AccountRestricted();

/// @dev Emitted when `account` is added to `blacklist`
event Restricted(address indexed account);
/// @dev Emitted when `account` is removed from `blacklist`
event Unrestricted(address indexed account);

/// @notice If an account is listed, it cannot send or receive tokens
/// ------------------ State ------------------ ///

/// @notice Accounts in `blacklist` cannot send or receive tokens
mapping(address => bool) public blacklist;

/// ------------------ Initialization ------------------ ///

constructor(address owner) {
_transferOwnership(owner);
}

/*//////////////////////////////////////////////////////////////
OPERATIONS CALLED BY OWNER
//////////////////////////////////////////////////////////////*/
/// ------------------ Setters ------------------ ///

/// @notice Restrict `account` from sending or receiving tokens
/// @dev Does not check if `account` is restricted
function restrict(address account) external onlyOwner {
blacklist[account] = true;
emit Restricted(account);
}

/// @notice Unrestrict `account` from sending or receiving tokens
/// @dev Does not check if `account` is restricted
function unrestrict(address account) external onlyOwner {
blacklist[account] = false;
emit Unrestricted(account);
}

/*//////////////////////////////////////////////////////////////
USED BY INTERFACE
//////////////////////////////////////////////////////////////*/
/// ------------------ Transfer Restriction ------------------ ///

/// @inheritdoc ITransferRestrictor
function requireNotRestricted(address from, address to) external view virtual {
// Check if either account is restricted
if (blacklist[from] || blacklist[to]) {
revert AccountRestricted();
}
Expand Down
Loading