Skip to content

Commit

Permalink
add token factory
Browse files Browse the repository at this point in the history
  • Loading branch information
RensR committed Nov 29, 2024
1 parent bca2fe0 commit 3732948
Show file tree
Hide file tree
Showing 25 changed files with 1,911 additions and 4 deletions.
37 changes: 37 additions & 0 deletions contracts/gas-snapshots/ccip.gas-snapshot
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,35 @@ EtherSenderReceiverTest_validatedMessage:test_validatedMessage_emptyDataOverwrit
EtherSenderReceiverTest_validatedMessage:test_validatedMessage_invalidTokenAmounts() (gas: 17925)
EtherSenderReceiverTest_validatedMessage:test_validatedMessage_tokenOverwrittenToWeth() (gas: 25329)
EtherSenderReceiverTest_validatedMessage:test_validatedMessage_validMessage_extraArgs() (gas: 26370)
FactoryBurnMintERC20_approve:test_Approve_Success() (gas: 55766)
FactoryBurnMintERC20_approve:test_InvalidAddress_Reverts() (gas: 10709)
FactoryBurnMintERC20_burn:test_BasicBurn_Success() (gas: 172367)
FactoryBurnMintERC20_burn:test_BurnFromZeroAddress_Reverts() (gas: 47272)
FactoryBurnMintERC20_burn:test_ExceedsBalance_Reverts() (gas: 21939)
FactoryBurnMintERC20_burn:test_SenderNotBurner_Reverts() (gas: 13493)
FactoryBurnMintERC20_burnFrom:test_BurnFrom_Success() (gas: 58231)
FactoryBurnMintERC20_burnFrom:test_ExceedsBalance_Reverts() (gas: 36138)
FactoryBurnMintERC20_burnFrom:test_InsufficientAllowance_Reverts() (gas: 22031)
FactoryBurnMintERC20_burnFrom:test_SenderNotBurner_Reverts() (gas: 13460)
FactoryBurnMintERC20_burnFromAlias:test_BurnFrom_Success() (gas: 58205)
FactoryBurnMintERC20_burnFromAlias:test_ExceedsBalance_Reverts() (gas: 36102)
FactoryBurnMintERC20_burnFromAlias:test_InsufficientAllowance_Reverts() (gas: 21986)
FactoryBurnMintERC20_burnFromAlias:test_SenderNotBurner_Reverts() (gas: 13415)
FactoryBurnMintERC20_constructor:test_Constructor_Success() (gas: 1475646)
FactoryBurnMintERC20_decreaseApproval:test_DecreaseApproval_Success() (gas: 31340)
FactoryBurnMintERC20_getCCIPAdmin:test_getCCIPAdmin_Success() (gas: 12684)
FactoryBurnMintERC20_getCCIPAdmin:test_setCCIPAdmin_Success() (gas: 23757)
FactoryBurnMintERC20_grantMintAndBurnRoles:test_GrantMintAndBurnRoles_Success() (gas: 121084)
FactoryBurnMintERC20_grantRole:test_GrantBurnAccess_Success() (gas: 53341)
FactoryBurnMintERC20_grantRole:test_GrantMany_Success() (gas: 961332)
FactoryBurnMintERC20_grantRole:test_GrantMintAccess_Success() (gas: 94068)
FactoryBurnMintERC20_increaseApproval:test_IncreaseApproval_Success() (gas: 44345)
FactoryBurnMintERC20_mint:test_BasicMint_Success() (gas: 149777)
FactoryBurnMintERC20_mint:test_MaxSupplyExceeded_Reverts() (gas: 50681)
FactoryBurnMintERC20_mint:test_SenderNotMinter_Reverts() (gas: 11372)
FactoryBurnMintERC20_supportsInterface:test_SupportsInterface_Success() (gas: 11439)
FactoryBurnMintERC20_transfer:test_InvalidAddress_Reverts() (gas: 10707)
FactoryBurnMintERC20_transfer:test_Transfer_Success() (gas: 42449)
FeeQuoter_applyDestChainConfigUpdates:test_InvalidChainFamilySelector_Revert() (gas: 16878)
FeeQuoter_applyDestChainConfigUpdates:test_InvalidDestChainConfigDestChainSelectorEqZero_Revert() (gas: 16780)
FeeQuoter_applyDestChainConfigUpdates:test_applyDestChainConfigUpdatesDefaultTxGasLimitEqZero_Revert() (gas: 16822)
Expand Down Expand Up @@ -957,6 +986,14 @@ TokenAdminRegistry_setPool:test_setPool_Success() (gas: 36135)
TokenAdminRegistry_setPool:test_setPool_ZeroAddressRemovesPool_Success() (gas: 30842)
TokenAdminRegistry_transferAdminRole:test_transferAdminRole_OnlyAdministrator_Revert() (gas: 18103)
TokenAdminRegistry_transferAdminRole:test_transferAdminRole_Success() (gas: 49438)
TokenPoolFactory_constructor:test_constructor_Revert() (gas: 1121620)
TokenPoolFactory_createTokenPool:test_createTokenPoolLockRelease_ExistingToken_predict_Success() (gas: 12535175)
TokenPoolFactory_createTokenPool:test_createTokenPool_BurnFromMintTokenPool_Success() (gas: 6414943)
TokenPoolFactory_createTokenPool:test_createTokenPool_ExistingRemoteToken_AndPredictPool_Success() (gas: 13284620)
TokenPoolFactory_createTokenPool:test_createTokenPool_RemoteTokenHasDifferentDecimals_Success() (gas: 13291989)
TokenPoolFactory_createTokenPool:test_createTokenPool_WithNoExistingRemoteContracts_predict_Success() (gas: 13622819)
TokenPoolFactory_createTokenPool:test_createTokenPool_WithNoExistingTokenOnRemoteChain_Success() (gas: 6201644)
TokenPoolFactory_createTokenPool:test_createTokenPool_WithRemoteTokenAndRemotePool_Success() (gas: 6411396)
TokenPoolWithAllowList_applyAllowListUpdates:test_AllowListNotEnabled_Revert() (gas: 2732579)
TokenPoolWithAllowList_applyAllowListUpdates:test_OnlyOwner_Revert() (gas: 12059)
TokenPoolWithAllowList_applyAllowListUpdates:test_SetAllowListSkipsZero_Success() (gas: 23512)
Expand Down
5 changes: 1 addition & 4 deletions contracts/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,7 @@
},
"files": [
"src/v0.8/ccip/**/*.sol",
"src/v0.8/shared/access/ConfirmedOwner.sol",
"src/v0.8/shared/access/ConfirmedOwnerWithProposal.sol",
"src/v0.8/shared/access/OwnerIsCreator.sol",
"src/v0.8/shared/access/AuthorizedCallers.sol",
"src/v0.8/shared/access/*.sol",
"src/v0.8/shared/call/CallWithExactGas.sol",
"src/v0.8/shared/enumerable/EnumerableMapBytes32.sol",
"src/v0.8/shared/enumerable/EnumerableMapAddresses.sol",
Expand Down
20 changes: 20 additions & 0 deletions contracts/src/v0.8/ccip/interfaces/ITokenAdminRegistry.sol
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,24 @@ interface ITokenAdminRegistry {
/// @param localToken The token to register the administrator for.
/// @param administrator The administrator to register.
function proposeAdministrator(address localToken, address administrator) external;

/// @notice Accepts the administrator role for a token.
/// @param localToken The token to accept the administrator role for.
/// @dev This function can only be called by the pending administrator.
function acceptAdminRole(
address localToken
) external;

/// @notice Sets the pool for a token. Setting the pool to address(0) effectively delists the token
/// from CCIP. Setting the pool to any other address enables the token on CCIP.
/// @param localToken The token to set the pool for.
/// @param pool The pool to set for the token.
function setPool(address localToken, address pool) external;

/// @notice Transfers the administrator role for a token to a new address with a 2-step process.
/// @param localToken The token to transfer the administrator role for.
/// @param newAdmin The address to transfer the administrator role to. Can be address(0) to cancel
/// a pending transfer.
/// @dev The new admin must call `acceptAdminRole` to accept the role.
function transferAdminRole(address localToken, address newAdmin) external;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.24;

import {FactoryBurnMintERC20} from "../../../tokenAdminRegistry/TokenPoolFactory/FactoryBurnMintERC20.sol";
import {BaseTest} from "../../BaseTest.t.sol";

contract BurnMintERC20Setup is BaseTest {
FactoryBurnMintERC20 internal s_burnMintERC20;

address internal s_mockPool = makeAddr("s_mockPool");
uint256 internal s_amount = 1e18;

address internal s_alice;

function setUp() public virtual override {
BaseTest.setUp();

s_alice = makeAddr("alice");

s_burnMintERC20 = new FactoryBurnMintERC20("Chainlink Token", "LINK", 18, 1e27, 0, s_alice);

// Set s_mockPool to be a burner and minter
s_burnMintERC20.grantMintAndBurnRoles(s_mockPool);
deal(address(s_burnMintERC20), OWNER, s_amount);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.24;

import {BurnMintERC20Setup} from "./BurnMintERC20Setup.t.sol";

contract FactoryBurnMintERC20_approve is BurnMintERC20Setup {
function test_Approve_Success() public {
uint256 balancePre = s_burnMintERC20.balanceOf(STRANGER);
uint256 sendingAmount = s_amount / 2;

s_burnMintERC20.approve(STRANGER, sendingAmount);

changePrank(STRANGER);

s_burnMintERC20.transferFrom(OWNER, STRANGER, sendingAmount);

assertEq(sendingAmount + balancePre, s_burnMintERC20.balanceOf(STRANGER));
}

// Reverts

function test_InvalidAddress_Reverts() public {
vm.expectRevert();

s_burnMintERC20.approve(address(s_burnMintERC20), s_amount);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.24;

import {IERC20} from "../../../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/IERC20.sol";
import {FactoryBurnMintERC20} from "../../../tokenAdminRegistry/TokenPoolFactory/FactoryBurnMintERC20.sol";
import {BurnMintERC20Setup} from "./BurnMintERC20Setup.t.sol";

contract FactoryBurnMintERC20_burn is BurnMintERC20Setup {
function test_BasicBurn_Success() public {
s_burnMintERC20.grantBurnRole(OWNER);
deal(address(s_burnMintERC20), OWNER, s_amount);

vm.expectEmit();
emit IERC20.Transfer(OWNER, address(0), s_amount);

s_burnMintERC20.burn(s_amount);

assertEq(0, s_burnMintERC20.balanceOf(OWNER));
}

// Revert

function test_SenderNotBurner_Reverts() public {
vm.expectRevert(abi.encodeWithSelector(FactoryBurnMintERC20.SenderNotBurner.selector, OWNER));

s_burnMintERC20.burnFrom(STRANGER, s_amount);
}

function test_ExceedsBalance_Reverts() public {
changePrank(s_mockPool);

vm.expectRevert("ERC20: burn amount exceeds balance");

s_burnMintERC20.burn(s_amount * 2);
}

function test_BurnFromZeroAddress_Reverts() public {
s_burnMintERC20.grantBurnRole(address(0));
changePrank(address(0));

vm.expectRevert("ERC20: burn from the zero address");

s_burnMintERC20.burn(0);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.24;

import {FactoryBurnMintERC20} from "../../../tokenAdminRegistry/TokenPoolFactory/FactoryBurnMintERC20.sol";
import {BurnMintERC20Setup} from "./BurnMintERC20Setup.t.sol";

contract FactoryBurnMintERC20_burnFrom is BurnMintERC20Setup {
function setUp() public virtual override {
BurnMintERC20Setup.setUp();
}

function test_BurnFrom_Success() public {
s_burnMintERC20.approve(s_mockPool, s_amount);

changePrank(s_mockPool);

s_burnMintERC20.burnFrom(OWNER, s_amount);

assertEq(0, s_burnMintERC20.balanceOf(OWNER));
}

// Reverts

function test_SenderNotBurner_Reverts() public {
vm.expectRevert(abi.encodeWithSelector(FactoryBurnMintERC20.SenderNotBurner.selector, OWNER));

s_burnMintERC20.burnFrom(OWNER, s_amount);
}

function test_InsufficientAllowance_Reverts() public {
changePrank(s_mockPool);

vm.expectRevert("ERC20: insufficient allowance");

s_burnMintERC20.burnFrom(OWNER, s_amount);
}

function test_ExceedsBalance_Reverts() public {
s_burnMintERC20.approve(s_mockPool, s_amount * 2);

changePrank(s_mockPool);

vm.expectRevert("ERC20: burn amount exceeds balance");

s_burnMintERC20.burnFrom(OWNER, s_amount * 2);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.24;

import {FactoryBurnMintERC20} from "../../../tokenAdminRegistry/TokenPoolFactory/FactoryBurnMintERC20.sol";
import {BurnMintERC20Setup} from "./BurnMintERC20Setup.t.sol";

contract FactoryBurnMintERC20_burnFromAlias is BurnMintERC20Setup {
function setUp() public virtual override {
BurnMintERC20Setup.setUp();
}

function test_BurnFrom_Success() public {
s_burnMintERC20.approve(s_mockPool, s_amount);

changePrank(s_mockPool);

s_burnMintERC20.burn(OWNER, s_amount);

assertEq(0, s_burnMintERC20.balanceOf(OWNER));
}

// Reverts

function test_SenderNotBurner_Reverts() public {
vm.expectRevert(abi.encodeWithSelector(FactoryBurnMintERC20.SenderNotBurner.selector, OWNER));

s_burnMintERC20.burn(OWNER, s_amount);
}

function test_InsufficientAllowance_Reverts() public {
changePrank(s_mockPool);

vm.expectRevert("ERC20: insufficient allowance");

s_burnMintERC20.burn(OWNER, s_amount);
}

function test_ExceedsBalance_Reverts() public {
s_burnMintERC20.approve(s_mockPool, s_amount * 2);

changePrank(s_mockPool);

vm.expectRevert("ERC20: burn amount exceeds balance");

s_burnMintERC20.burn(OWNER, s_amount * 2);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.24;

import {FactoryBurnMintERC20} from "../../../tokenAdminRegistry/TokenPoolFactory/FactoryBurnMintERC20.sol";
import {BurnMintERC20Setup} from "./BurnMintERC20Setup.t.sol";

contract FactoryBurnMintERC20_constructor is BurnMintERC20Setup {
function test_Constructor_Success() public {
string memory name = "Chainlink token v2";
string memory symbol = "LINK2";
uint8 decimals = 19;
uint256 maxSupply = 1e33;

s_burnMintERC20 = new FactoryBurnMintERC20(name, symbol, decimals, maxSupply, 1e18, s_alice);

assertEq(name, s_burnMintERC20.name());
assertEq(symbol, s_burnMintERC20.symbol());
assertEq(decimals, s_burnMintERC20.decimals());
assertEq(maxSupply, s_burnMintERC20.maxSupply());

assertTrue(s_burnMintERC20.isMinter(s_alice));
assertTrue(s_burnMintERC20.isBurner(s_alice));
assertEq(s_burnMintERC20.balanceOf(s_alice), 1e18);
assertEq(s_burnMintERC20.totalSupply(), 1e18);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.24;

import {BurnMintERC20Setup} from "./BurnMintERC20Setup.t.sol";

contract FactoryBurnMintERC20_decreaseApproval is BurnMintERC20Setup {
function test_DecreaseApproval_Success() public {
s_burnMintERC20.approve(s_mockPool, s_amount);
uint256 allowance = s_burnMintERC20.allowance(OWNER, s_mockPool);
assertEq(allowance, s_amount);
s_burnMintERC20.decreaseApproval(s_mockPool, s_amount);
assertEq(s_burnMintERC20.allowance(OWNER, s_mockPool), allowance - s_amount);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.24;

import {FactoryBurnMintERC20} from "../../../tokenAdminRegistry/TokenPoolFactory/FactoryBurnMintERC20.sol";
import {BurnMintERC20Setup} from "./BurnMintERC20Setup.t.sol";

contract FactoryBurnMintERC20_getCCIPAdmin is BurnMintERC20Setup {
function test_getCCIPAdmin_Success() public view {
assertEq(s_alice, s_burnMintERC20.getCCIPAdmin());
}

function test_setCCIPAdmin_Success() public {
address newAdmin = makeAddr("newAdmin");

vm.expectEmit();
emit FactoryBurnMintERC20.CCIPAdminTransferred(s_alice, newAdmin);

s_burnMintERC20.setCCIPAdmin(newAdmin);

assertEq(newAdmin, s_burnMintERC20.getCCIPAdmin());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.24;

import {FactoryBurnMintERC20} from "../../../tokenAdminRegistry/TokenPoolFactory/FactoryBurnMintERC20.sol";
import {BurnMintERC20Setup} from "./BurnMintERC20Setup.t.sol";

contract FactoryBurnMintERC20_grantMintAndBurnRoles is BurnMintERC20Setup {
function test_GrantMintAndBurnRoles_Success() public {
assertFalse(s_burnMintERC20.isMinter(STRANGER));
assertFalse(s_burnMintERC20.isBurner(STRANGER));

vm.expectEmit();
emit FactoryBurnMintERC20.MintAccessGranted(STRANGER);
vm.expectEmit();
emit FactoryBurnMintERC20.BurnAccessGranted(STRANGER);

s_burnMintERC20.grantMintAndBurnRoles(STRANGER);

assertTrue(s_burnMintERC20.isMinter(STRANGER));
assertTrue(s_burnMintERC20.isBurner(STRANGER));
}
}
Loading

0 comments on commit 3732948

Please sign in to comment.