Skip to content

Commit

Permalink
Implement Retire on Removal.sol for direct retirement (#733)
Browse files Browse the repository at this point in the history
* tests, snapshot, docgen

* fix build

* fix vesting task

* restore Migrate event

* changes to migrate-certificates.ts

* snapshot and docgen

---------

Co-authored-by: amiecorso <[email protected]>
  • Loading branch information
amiecorso and amiecorso authored Mar 7, 2024
1 parent fd34ba0 commit 447f6fb
Show file tree
Hide file tree
Showing 7 changed files with 156 additions and 113 deletions.
160 changes: 80 additions & 80 deletions .gas-snapshot
Original file line number Diff line number Diff line change
Expand Up @@ -20,36 +20,36 @@ Certificate_supportsInterface:test() (gas: 5159)
Certificate_transferFrom:test() (gas: 48618)
Certificate_transferFrom:test_reverts_when_paused() (gas: 38088)
Certificate_transferFrom_reverts_ForbiddenTransferAfterMinting:test() (gas: 18960)
Checkout_buyingFromOneRemoval:test() (gas: 652994)
Checkout_buyingFromOneRemoval_byApproval:test() (gas: 589052)
Checkout_buyingFromTenRemovals:test() (gas: 1976346)
Checkout_buyingFromTenRemovals_singleSupplier:test() (gas: 1711916)
Checkout_buyingFromTenRemovals_singleSupplier_withoutFee:test() (gas: 1707116)
Checkout_buyingFromTenRemovals_withoutFee:test() (gas: 1719822)
Checkout_buyingFromTenSuppliers:test() (gas: 2854632)
Checkout_buyingWithAlternateERC20:test() (gas: 546928)
Checkout_buyingWithAlternateERC20_floatingPointPriceMultiple:test() (gas: 512982)
Checkout_buyingFromOneRemoval:test() (gas: 653182)
Checkout_buyingFromOneRemoval_byApproval:test() (gas: 589240)
Checkout_buyingFromTenRemovals:test() (gas: 1978293)
Checkout_buyingFromTenRemovals_singleSupplier:test() (gas: 1713863)
Checkout_buyingFromTenRemovals_singleSupplier_withoutFee:test() (gas: 1709063)
Checkout_buyingFromTenRemovals_withoutFee:test() (gas: 1721769)
Checkout_buyingFromTenSuppliers:test() (gas: 2856579)
Checkout_buyingWithAlternateERC20:test() (gas: 547028)
Checkout_buyingWithAlternateERC20_floatingPointPriceMultiple:test() (gas: 513082)
Checkout_swapRevertsWhenBuyerIsMissingSANCTION_ALLOWLIST_ROLE:test() (gas: 168598)
Checkout_swapRevertsWithDifferentPermitSignerAndMsgSender:test() (gas: 168610)
Checkout_swapWithoutFeeSpecialOrder:test() (gas: 569131)
Checkout_swapWithoutFeeSpecialOrder_specificSupplier:test() (gas: 563830)
Checkout_swapWithoutFeeSpecialOrder:test() (gas: 569319)
Checkout_swapWithoutFeeSpecialOrder_specificSupplier:test() (gas: 564018)
Checkout_swapWithoutFeeSpecialOrder_specificSupplier:test_revertsWhenSupplierDoesNotExistInMarket() (gas: 57731)
Checkout_swapWithoutFeeSpecialOrder_specificVintages:test_basicFulfillment() (gas: 965410)
Checkout_swapWithoutFeeSpecialOrder_specificVintages:test_basicFulfillment() (gas: 965796)
Checkout_swapWithoutFeeSpecialOrder_specificVintages:test_revertsWhenNoRemovalsFromSpecifiedVintages() (gas: 91000)
Checkout_swapWithoutFeeSpecialOrder_specificVintagesSpecificSupplier:test_basicFulfillment() (gas: 701767)
Checkout_swapWithoutFeeSpecialOrder_specificVintagesSpecificSupplier:test_basicFulfillment() (gas: 702054)
LockedNORILib_availableAmount:test() (gas: 12371)
LockedNORITest:testBatchGrantCreation() (gas: 705179)
LockedNORITest:testNormalWithdrawal() (gas: 1102743)
LockedNORITest:testReentryTokensReceived() (gas: 1102887)
LockedNORITest:testReentryTokensToSend() (gas: 1104432)
LockedNORITest:testTokensReceivedReverts() (gas: 69026)
MarketInvariantTest:invariant_callSummary() (runs: 400, calls: 6000, reverts: 4269)
MarketInvariantTest:invariant_sumOfPurchaseAmounts() (runs: 400, calls: 6000, reverts: 4292)
MarketSupplierSelectionNotUsingUpSuppliersLastRemoval:test() (gas: 923444)
MarketInvariantTest:invariant_callSummary() (runs: 400, calls: 6000, reverts: 4267)
MarketInvariantTest:invariant_sumOfPurchaseAmounts() (runs: 400, calls: 6000, reverts: 4261)
MarketSupplierSelectionNotUsingUpSuppliersLastRemoval:test() (gas: 923731)
Market_ALLOWLIST_ROLE:test() (gas: 12799)
Market_SANCTION_ALLOWLIST_ROLE:test() (gas: 12897)
Market_USDC_swap_respects_decimal_mismatch:test() (gas: 799139)
Market_USDC_swap_withholds_restricted_nori:test() (gas: 974214)
Market_USDC_swap_respects_decimal_mismatch:test() (gas: 799239)
Market_USDC_swap_withholds_restricted_nori:test() (gas: 974402)
Market__addActiveRemoval:test() (gas: 183344)
Market__addActiveRemoval:test__lis2VintagesFor1SupplierFor2SubIdentifiers() (gas: 242901)
Market__addActiveRemoval:test__list1VintageFor1Supplier() (gas: 188309)
Expand All @@ -73,48 +73,48 @@ Market__validateSupply:test_reverts_OutOfSupply() (gas: 3194)
Market_calculates_prices_using_decimal:test() (gas: 66492)
Market_convertPurchasingTokenDecimalsToRemovalDecimals:test() (gas: 26029)
Market_convertRemovalDecimalsToPurchasingTokenDecimals:test() (gas: 29773)
Market_getActiveSuppliers:test_1_supplier() (gas: 610132)
Market_getActiveSuppliers:test_3_suppliers() (gas: 1262512)
Market_getActiveSuppliers:test_1_supplier() (gas: 610143)
Market_getActiveSuppliers:test_3_suppliers() (gas: 1262545)
Market_getActiveSuppliers:test_no_suppliers() (gas: 20837)
Market_getPriceMultiple:test() (gas: 14873)
Market_getRemovalIdsForSupplier:test_1_removal() (gas: 610557)
Market_getRemovalIdsForSupplier:test_3_removals() (gas: 993990)
Market_getRemovalIdsForSupplier:test_3_removals_different_vintages() (gas: 1040099)
Market_getRemovalIdsForSupplier:test_1_removal() (gas: 610568)
Market_getRemovalIdsForSupplier:test_3_removals() (gas: 994023)
Market_getRemovalIdsForSupplier:test_3_removals_different_vintages() (gas: 1040132)
Market_getRemovalIdsForSupplier:test_no_removals() (gas: 26044)
Market_onERC1155BatchReceived:test() (gas: 208168)
Market_onERC1155BatchReceived_reverts_SenderNotRemovalContract:test() (gas: 355367)
Market_onERC1155BatchReceived_reverts_SenderNotRemovalContract:test() (gas: 355477)
Market_onERC1155Received:test() (gas: 206036)
Market_onERC1155Received_reverts_SenderNotRemovalContract:test() (gas: 159000)
Market_purchasingTokenAddress:test() (gas: 17191)
Market_replace:test() (gas: 345000)
Market_replace:test() (gas: 345188)
Market_replace_reverts_CertificateNotYetMinted:test() (gas: 49559)
Market_replace_reverts_ReplacementAmountExceedsNrtDeficit:test() (gas: 52590)
Market_replace_reverts_ReplacementAmountMismatch:test() (gas: 86353)
Market_setNoriFeePercentage_revertsInvalidPercentage:test() (gas: 20254)
Market_setPriorityRestrictedThreshold:test() (gas: 157403)
Market_setPriorityRestrictedThreshold:test_zeroAvailable() (gas: 152378)
Market_setPriorityRestrictedThreshold:test() (gas: 157359)
Market_setPriorityRestrictedThreshold:test_zeroAvailable() (gas: 152334)
Market_setPurchasingTokenAndPriceMultiple:test() (gas: 1026588)
Market_setPurchasingTokenAndPriceMultiple_revertsIfNotAdmin:test() (gas: 50791)
Market_supplierSelectionUsingUpSuppliersLastRemoval:test() (gas: 920153)
Market_swapWithoutFeeSpecialOrder_emits_and_skips_transfer_when_transferring_wrong_erc20_to_rNori:test() (gas: 421070)
Market_swap_emits_and_skips_transfer_when_transferring_wrong_erc20_to_rNori:test() (gas: 521672)
Market_swap_emits_event_and_skips_mint_when_minting_rNori_to_nonERC1155Receiver:test() (gas: 598957)
Market_supplierSelectionUsingUpSuppliersLastRemoval:test() (gas: 920440)
Market_swapWithoutFeeSpecialOrder_emits_and_skips_transfer_when_transferring_wrong_erc20_to_rNori:test() (gas: 421170)
Market_swap_emits_and_skips_transfer_when_transferring_wrong_erc20_to_rNori:test() (gas: 521772)
Market_swap_emits_event_and_skips_mint_when_minting_rNori_to_nonERC1155Receiver:test() (gas: 599145)
Market_swap_revertsWhenUnsafeERC20TransferFails:test() (gas: 218819)
Market_validates_certificate_amount:test() (gas: 596888)
Market_withdraw_1x3_center:test() (gas: 340858)
Market_withdraw_2x1_back:test() (gas: 345518)
Market_withdraw_2x1_front:test() (gas: 333875)
Market_withdraw_2x1_front_relist:test() (gas: 381810)
Market_withdraw_as_DEFAULT_ADMIN_ROLE:test() (gas: 276568)
Market_withdraw_as_operator:test() (gas: 285735)
Market_withdraw_as_supplier:test() (gas: 274709)
Market_withdraw_reverts:test() (gas: 138753)
Market_withdraw_1x3_center:test() (gas: 340825)
Market_withdraw_2x1_back:test() (gas: 345485)
Market_withdraw_2x1_front:test() (gas: 333842)
Market_withdraw_2x1_front_relist:test() (gas: 381777)
Market_withdraw_as_DEFAULT_ADMIN_ROLE:test() (gas: 276535)
Market_withdraw_as_operator:test() (gas: 285702)
Market_withdraw_as_supplier:test() (gas: 274676)
Market_withdraw_reverts:test() (gas: 138709)
NORI_name:test() (gas: 17205)
NORI_permit:test() (gas: 92382)
NoriUSDC_permit:test() (gas: 122061)
RemovalQueue_getTotalBalanceFromRemovalQueue:test() (gas: 23899)
RemovalQueue_getTotalBalanceFromRemovalQueue:test_100xRemovalsOfTheDifferentVintages() (gas: 895786)
RemovalQueue_getTotalBalanceFromRemovalQueue:test_100xRemovalsOfTheSameVintage() (gas: 620299)
RemovalQueue_getTotalBalanceFromRemovalQueue:test() (gas: 23877)
RemovalQueue_getTotalBalanceFromRemovalQueue:test_100xRemovalsOfTheDifferentVintages() (gas: 895764)
RemovalQueue_getTotalBalanceFromRemovalQueue:test_100xRemovalsOfTheSameVintage() (gas: 620277)
RemovalQueue_insertRemovalByVintage:test_insertRemovalOnce() (gas: 119613)
RemovalQueue_insertRemovalByVintage:test_insertRemovalTwice() (gas: 121125)
Removal__beforeTokenTransfer:test() (gas: 18010)
Expand All @@ -124,68 +124,68 @@ Removal__createRemovalData:test_reverts_InvalidData() (gas: 25711)
Removal__createRemovalDataBatch:test() (gas: 29572)
Removal__createRemovalDataBatch:test_reverts_InvalidData2() (gas: 36714)
Removal__isValidTransferAmount:testFuzz_ReturnFalse_NonMultiplesOf1e14(uint256) (runs: 256, μ: 13891, ~: 13847)
Removal__isValidTransferAmount:testFuzz_ReturnTrue_MultiplesOf1e14(uint256) (runs: 256, μ: 14380, ~: 14497)
Removal__isValidTransferAmount:testFuzz_ReturnTrue_MultiplesOf1e14(uint256) (runs: 256, μ: 14369, ~: 14497)
Removal__isValidTransferAmount:testFuzz_ReturnTrue_SmallestGranularity() (gas: 6832)
Removal__isValidTransferAmount:test_ReturnFalse_AmountIsTooGranular() (gas: 6898)
Removal__isValidTransferAmount:test_ReturnFalse_AmountIsTooGranularAndToIsTheCertificate() (gas: 4745)
Removal__isValidTransferAmount:test_ReturnFalse_AmountIsTooGranularAndToIsTheMarket() (gas: 2608)
Removal__isValidTransferAmount:test_ReturnFalse_AmountIsZeroAndToIsTheCertificate() (gas: 4705)
Removal__isValidTransferAmount:test_ReturnFalse_AmountIsZeroAndToIsTheCertificate() (gas: 4683)
Removal__isValidTransferAmount:test_ReturnFalse_AmountIsZeroAndToIsTheMarket() (gas: 2521)
Removal__isValidTransferAmount:test_ReturnTrue_AmountIsZeroAndToIsNeitherTheMarketNorCertificate() (gas: 6852)
Removal__validateRemoval:test() (gas: 2491)
Removal__validateRemoval:test_reverts_InvalidData() (gas: 5373)
Removal_addBalance:test() (gas: 60280)
Removal_addBalance_reverts_RemovalNotYetMinted:test() (gas: 31115)
Removal_addBalance:test() (gas: 60269)
Removal_addBalance_reverts_RemovalNotYetMinted:test() (gas: 31093)
Removal_batchGetHoldbackPercentages_multipleIds:test() (gas: 11098)
Removal_batchGetHoldbackPercentages_singleId:test() (gas: 10346)
Removal_consign_revertsForSoldRemovals:test() (gas: 1172740)
Removal_getMarketBalance:test() (gas: 1185770)
Removal_getOwnedTokenIds:test_multiple_tokens_with_transfer() (gas: 1078643)
Removal_getOwnedTokenIds:test_no_tokens() (gas: 18683)
Removal_getProjectId:test() (gas: 19307)
Removal_grantRole:test_reverts_when_paused() (gas: 26272)
Removal_migrate:test() (gas: 989116)
Removal_migrate_gasLimit:test() (gas: 15359829)
Removal_migrate_revertsIfRemovalBalanceSumDifferentFromCertificateAmount:test() (gas: 1002846)
Removal_mintBatch:test() (gas: 348611)
Removal_mintBatch_list:test() (gas: 557922)
Removal_mintBatch_list_sequential:test() (gas: 749158)
Removal_mintBatch_multiple:test_16() (gas: 3083542)
Removal_mintBatch_multiple:test_2() (gas: 726249)
Removal_mintBatch_multiple:test_32() (gas: 5778699)
Removal_mintBatch_multiple:test_4() (gas: 1062966)
Removal_mintBatch_multiple:test_8() (gas: 1736405)
Removal_consign_revertsForSoldRemovals:test() (gas: 1172950)
Removal_getMarketBalance:test() (gas: 1185991)
Removal_getOwnedTokenIds:test_multiple_tokens_with_transfer() (gas: 1079154)
Removal_getOwnedTokenIds:test_no_tokens() (gas: 18772)
Removal_getProjectId:test() (gas: 19395)
Removal_grantRole:test_reverts_when_paused() (gas: 26250)
Removal_mintBatch:test() (gas: 348622)
Removal_mintBatch_list:test() (gas: 557933)
Removal_mintBatch_list_sequential:test() (gas: 749180)
Removal_mintBatch_multiple:test_16() (gas: 3083718)
Removal_mintBatch_multiple:test_2() (gas: 726271)
Removal_mintBatch_multiple:test_32() (gas: 5779051)
Removal_mintBatch_multiple:test_4() (gas: 1063010)
Removal_mintBatch_multiple:test_8() (gas: 1736493)
Removal_mintBatch_revertsInvalidHoldbackPercentage:test() (gas: 56204)
Removal_mintBatch_reverts_mint_to_wrong_address:test() (gas: 89002)
Removal_mintBatch_zero_amount_removal:test() (gas: 311185)
Removal_mintBatch_zero_amount_removal:test() (gas: 311196)
Removal_mintBatch_zero_amount_removal_to_market_reverts:test() (gas: 85435)
Removal_multicall:test_balanceOfBatch() (gas: 492005)
Removal_release_listed:test() (gas: 486531)
Removal_release_listed_isRemovedFromMarket:test() (gas: 486885)
Removal_release_partial_listed:test() (gas: 79637)
Removal_release_retired:test() (gas: 92425)
Removal_release_retired_2x:test() (gas: 98489)
Removal_release_retired_burned:test() (gas: 94905)
Removal_release_retired_burned:testDecrementsCertificateDiscrepancy() (gas: 88947)
Removal_release_retired_oneHundredCertificates:test() (gas: 89535)
Removal_release_reverts_AccessControl:test() (gas: 48757)
Removal_release_unlisted:test() (gas: 48617)
Removal_release_unlisted_listed_and_retired:test() (gas: 237568)
Removal_renounceRole:test_reverts_when_paused() (gas: 19688)
Removal_multicall:test_balanceOfBatch() (gas: 491983)
Removal_release_listed:test() (gas: 486522)
Removal_release_listed_isRemovedFromMarket:test() (gas: 486876)
Removal_release_partial_listed:test() (gas: 79615)
Removal_release_retired:test() (gas: 92381)
Removal_release_retired_2x:test() (gas: 98467)
Removal_release_retired_burned:test() (gas: 94861)
Removal_release_retired_burned:testDecrementsCertificateDiscrepancy() (gas: 88925)
Removal_release_retired_oneHundredCertificates:test() (gas: 89491)
Removal_release_reverts_AccessControl:test() (gas: 48735)
Removal_release_unlisted:test() (gas: 48600)
Removal_release_unlisted_listed_and_retired:test() (gas: 237533)
Removal_renounceRole:test_reverts_when_paused() (gas: 19666)
Removal_retire:test() (gas: 989180)
Removal_retire_gasLimit:test() (gas: 15361939)
Removal_retire_revertsIfRemovalBalanceSumDifferentFromCertificateAmount:test() (gas: 1002910)
Removal_revokeRole:test_reverts_when_paused() (gas: 26840)
Removal_safeBatchTransferFrom_reverts_ForbiddenTransfer:test() (gas: 32073)
Removal_safeBatchTransferFrom_reverts_ForbiddenTransfer:test() (gas: 32162)
Removal_safeTransferFrom_reverts_ForbiddenTransfer:test() (gas: 27738)
Removal_setHoldbackPercentage:test() (gas: 37877)
Removal_setHoldbackPercentage:test_reverts_InvalidHoldbackPercentage() (gas: 29163)
RestrictedNORI__validateSchedule:test_startTimeNotZero() (gas: 269)
RestrictedNORI__validateSchedule_reverts:test_restrictionDurationZero() (gas: 3362)
RestrictedNORI__validateSchedule_reverts:test_startTimeZero() (gas: 3384)
RestrictedNORI_createSchedule:test_RevertWhen_MethodologyVersionHasNoDurationSet() (gas: 26650)
RestrictedNORI_createSchedule:test_RevertWhen_ScheduleExists() (gas: 43800)
RestrictedNORI_createSchedule:test_RevertWhen_ScheduleExists() (gas: 43888)
RestrictedNORI_getUnderlyingTokenAddress:test() (gas: 17124)
RestrictedNORI_initialize:test() (gas: 21827)
RestrictedNORI_linearReleaseAmountAvailable:test() (gas: 11920)
RestrictedNORI_revokeUnreleasedTokens:test() (gas: 246318)
RestrictedNORI_revokeUnreleasedTokens:test() (gas: 246406)
RestrictedNORI_scheduleExists:test() (gas: 15177)
RestrictedNORI_scheduleExists:test_doesntExist() (gas: 15156)
RestrictedNORI_transfers_revert:testSafeBatchTransferFromReverts() (gas: 29158)
Expand Down
31 changes: 23 additions & 8 deletions contracts/Removal.sol
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,22 @@ contract Removal is
uint256[] removalAmounts
);

/**
* @notice Emitted when removals are directly retired into a certificate by Nori.
* @param certificateRecipient The recipient of the certificate.
* @param certificateAmount The total amount of the certificate to mint (denominated in RTs).
* @param certificateId The ID of the certificate being minted.
* @param removalIds The removal IDs to use to mint the certificate.
* @param removalAmounts The amounts to retire from each corresponding removal ID.
*/
event Retire(
address indexed certificateRecipient,
uint256 indexed certificateAmount,
uint256 indexed certificateId,
uint256[] removalIds,
uint256[] removalAmounts
);

/**
* @notice Locks the contract, preventing any future re-initialization.
* @dev See more [here](https://docs.openzeppelin.com/contracts/4.x/api/proxy#Initializable-_disableInitializers--).
Expand Down Expand Up @@ -381,19 +397,18 @@ contract Removal is

/**
* @notice Transfers the provided `amounts` (denominated in NRTs) of the specified removal `ids` directly to the
* Certificate contract to mint a legacy certificate. This function provides Nori the ability to execute a one-off
* migration of legacy certificates and removals (legacy certificates and removals are those which existed prior to
* our deployment to Polygon and covers all historic issuances and purchases up until the date that we start using the
* Market contract).
* Certificate contract to mint a certificate. This function provides Nori the ability to retire removals directly
* into the Certificate contract and to specify exactly which removals will be retired.
* @dev The Certificate contract implements `onERC1155BatchReceived`, which is invoked upon receipt of a batch of
* removals (triggered via `_safeBatchTransferFrom`). This function circumvents the market contract's lifecycle by
* removals (triggered via `_safeBatchTransferFrom`). This function circumvents the market contract by
* transferring the removals from an account with the `CONSIGNOR_ROLE` role.
* Emits a `Retire` event.
*
* It is necessary that the consignor holds the removals because of the following:
* - `ids` can be composed of a list of removal IDs that belong to one or more suppliers.
* - `_safeBatchTransferFrom` only accepts one `from` address.
* - `Certificate.onERC1155BatchReceived` will mint a *new* certificate every time an additional batch is received, so
* we must ensure that all the removals comprising the certificate to be migrated come from a single batch.
* we must ensure that all the removals comprising the certificate come from a single batch.
*
* ##### Requirements:
* - The caller must have the `CONSIGNOR_ROLE` role.
Expand All @@ -407,13 +422,13 @@ contract Removal is
* @param certificateRecipient The recipient of the certificate to be minted.
* @param certificateAmount The total amount of the certificate.
*/
function migrate(
function retire(
uint256[] calldata ids,
uint256[] calldata amounts,
address certificateRecipient,
uint256 certificateAmount
) external onlyRole(CONSIGNOR_ROLE) {
emit Migrate({
emit Retire({
certificateRecipient: certificateRecipient,
certificateAmount: certificateAmount,
certificateId: _certificate.totalMinted(),
Expand Down
Loading

0 comments on commit 447f6fb

Please sign in to comment.