diff --git a/contracts/JBERC20PaymentTerminal3_2.sol b/contracts/JBERC20PaymentTerminal3_2.sol index 384ef035e..186f8bacb 100644 --- a/contracts/JBERC20PaymentTerminal3_2.sol +++ b/contracts/JBERC20PaymentTerminal3_2.sol @@ -4,17 +4,51 @@ pragma solidity ^0.8.16; import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol'; import {IERC20Metadata} from '@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol'; import {SafeERC20} from '@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol'; -import {JBPayoutRedemptionPaymentTerminal3_2} from './abstract/JBPayoutRedemptionPaymentTerminal3_2.sol'; +import {IPermit2, IAllowanceTransfer} from 'permit2/src/interfaces/IPermit2.sol'; +import {JBPayoutRedemptionPaymentTerminal3_2, IERC165} from './abstract/JBPayoutRedemptionPaymentTerminal3_2.sol'; import {IJBDirectory} from './interfaces/IJBDirectory.sol'; import {IJBOperatorStore} from './interfaces/IJBOperatorStore.sol'; import {IJBProjects} from './interfaces/IJBProjects.sol'; import {IJBSplitsStore} from './interfaces/IJBSplitsStore.sol'; import {IJBPrices} from './interfaces/IJBPrices.sol'; +import {IJBPermit2PaymentTerminal} from './interfaces/IJBPermit2PaymentTerminal.sol'; +import {JBSingleAllowanceData} from './structs/JBSingleAllowanceData.sol'; /// @notice Manages the inflows and outflows of an ERC-20 token. -contract JBERC20PaymentTerminal3_1_2 is JBPayoutRedemptionPaymentTerminal3_2 { +contract JBERC20PaymentTerminal3_1_2 is + JBPayoutRedemptionPaymentTerminal3_2, + IJBPermit2PaymentTerminal +{ using SafeERC20 for IERC20; + //*********************************************************************// + // --------------------------- custom errors ------------------------- // + //*********************************************************************// + + error PERMIT_ALLOWANCE_NOT_ENOUGH(uint256 _transactionAmount, uint256 _permitAllowance); + + //*********************************************************************// + // ---------------- public immutable stored properties --------------- // + //*********************************************************************// + + IPermit2 public immutable PERMIT2; + + //*********************************************************************// + // -------------------------- public views --------------------------- // + //*********************************************************************// + + /// @notice Indicates if this contract adheres to the specified interface. + /// @dev See {IERC165-supportsInterface}. + /// @param _interfaceId The ID of the interface to check for adherance to. + /// @return A flag indicating if the provided interface ID is supported. + function supportsInterface( + bytes4 _interfaceId + ) public view virtual override(JBPayoutRedemptionPaymentTerminal3_2, IERC165) returns (bool) { + return + _interfaceId == type(IJBPermit2PaymentTerminal).interfaceId || + super.supportsInterface(_interfaceId); + } + //*********************************************************************// // -------------------------- internal views ------------------------- // //*********************************************************************// @@ -47,7 +81,8 @@ contract JBERC20PaymentTerminal3_1_2 is JBPayoutRedemptionPaymentTerminal3_2 { IJBSplitsStore _splitsStore, IJBPrices _prices, address _store, - address _owner + address _owner, + IPermit2 _permit2 ) JBPayoutRedemptionPaymentTerminal3_2( address(_token), @@ -64,13 +99,104 @@ contract JBERC20PaymentTerminal3_1_2 is JBPayoutRedemptionPaymentTerminal3_2 { ) // solhint-disable-next-line no-empty-blocks { + PERMIT2 = _permit2; + } + + //*********************************************************************// + // ----------------------- public transactions ----------------------- // + //*********************************************************************// + + /// @notice Contribute tokens to a project and sets an allowance for this terminal (using Permit2). + /// @param _projectId The ID of the project being paid. + /// @param _amount The amount of terminal tokens being received, as a fixed point number with the same amount of decimals as this terminal. If this terminal's token is ETH, this is ignored and msg.value is used in its place. + /// @param _token The token being paid. This terminal ignores this property since it only manages one token. + /// @param _beneficiary The address to mint tokens for and pass along to the funding cycle's data source and delegate. + /// @param _minReturnedTokens The minimum number of project tokens expected in return, as a fixed point number with the same amount of decimals as this terminal. + /// @param _preferClaimedTokens A flag indicating whether the request prefers to mint project tokens into the beneficiaries wallet rather than leaving them unclaimed. This is only possible if the project has an attached token contract. Leaving them unclaimed saves gas. + /// @param _memo A memo to pass along to the emitted event, and passed along the the funding cycle's data source and delegate. A data source can alter the memo before emitting in the event and forwarding to the delegate. + /// @param _metadata Bytes to send along to the data source, delegate, and emitted event, if provided. + /// @param _allowance The allowance to set for this terminal (using Permit2). + /// @return The number of tokens minted for the beneficiary, as a fixed point number with 18 decimals. + function payAndSetAllowance( + uint256 _projectId, + uint256 _amount, + address _token, + address _beneficiary, + uint256 _minReturnedTokens, + bool _preferClaimedTokens, + string calldata _memo, + bytes calldata _metadata, + JBSingleAllowanceData calldata _allowance + ) external virtual returns (uint256) { + // If the `_allowance.amount` is less than `_amount` then + // setting the permit will still not result in a succeful payment + if (_amount < _allowance.amount) revert PERMIT_ALLOWANCE_NOT_ENOUGH(_amount, _allowance.amount); + // Get allowance to `spend` tokens for the sender + _permitAllowance(_allowance); + // Continue with the regular pay flow + return + pay( + _projectId, + _amount, + _token, + _beneficiary, + _minReturnedTokens, + _preferClaimedTokens, + _memo, + _metadata + ); + } + /// @notice Receives funds belonging to the specified project. + /// @param _projectId The ID of the project to which the funds received belong. + /// @param _amount The amount of tokens to add, as a fixed point number with the same number of decimals as this terminal. If this is an ETH terminal, this is ignored and msg.value is used instead. + /// @param _token The token being paid. This terminal ignores this property since it only manages one currency. + /// @param _shouldRefundHeldFees A flag indicating if held fees should be refunded based on the amount being added. + /// @param _memo A memo to pass along to the emitted event. + /// @param _metadata Extra data to pass along to the emitted event. + /// @param _allowance The allowance to set for this terminal (using Permit2). + function addToBalanceOfAndSetAllowance( + uint256 _projectId, + uint256 _amount, + address _token, + bool _shouldRefundHeldFees, + string calldata _memo, + bytes calldata _metadata, + JBSingleAllowanceData calldata _allowance + ) external virtual { + // If the `_allowance.amount` is less than `_amount` then + // setting the permit will still not result in a succeful payment + if (_amount < _allowance.amount) revert PERMIT_ALLOWANCE_NOT_ENOUGH(_amount, _allowance.amount); + // Get allowance to `spend` tokens for the user + _permitAllowance(_allowance); + // Continue with the regular addToBalanceOf flow + return addToBalanceOf(_projectId, _amount, _token, _shouldRefundHeldFees, _memo, _metadata); } //*********************************************************************// // ---------------------- internal transactions ---------------------- // //*********************************************************************// + /// @notice Gets allowance + /// @param _allowance the allowance to get using permit2 + function _permitAllowance(JBSingleAllowanceData calldata _allowance) internal { + // Use Permit2 to set the allowance + PERMIT2.permit( + msg.sender, + IAllowanceTransfer.PermitSingle({ + details: IAllowanceTransfer.PermitDetails({ + token: address(token), + amount: _allowance.amount, + expiration: _allowance.expiration, + nonce: _allowance.nonce + }), + spender: address(this), + sigDeadline: _allowance.sigDeadline + }), + _allowance.signature + ); + } + /// @notice Transfers tokens. /// @param _from The address from which the transfer should originate. /// @param _to The address to which the transfer should go. diff --git a/contracts/JBETHPaymentTerminal3_2.sol b/contracts/JBETHPaymentTerminal3_2.sol index 35aef45f8..3c94c9f1e 100644 --- a/contracts/JBETHPaymentTerminal3_2.sol +++ b/contracts/JBETHPaymentTerminal3_2.sol @@ -46,11 +46,10 @@ contract JBETHPaymentTerminal3_1_2 is JBPayoutRedemptionPaymentTerminal3_2 { address _store, address _owner ) - JBPayoutRedemptionPaymentTerminal3_1_2( + JBPayoutRedemptionPaymentTerminal3_2( JBTokens.ETH, 18, // 18 decimals. JBCurrencies.ETH, - _baseWeightCurrency, JBSplitsGroups.ETH_PAYOUT, _operatorStore, _projects, diff --git a/contracts/abstract/JBPayoutRedemptionPaymentTerminal3_1_2.sol b/contracts/abstract/JBPayoutRedemptionPaymentTerminal3_1_2.sol index 393822e05..ab02990b7 100644 --- a/contracts/abstract/JBPayoutRedemptionPaymentTerminal3_1_2.sol +++ b/contracts/abstract/JBPayoutRedemptionPaymentTerminal3_1_2.sol @@ -1504,10 +1504,8 @@ abstract contract JBPayoutRedemptionPaymentTerminal3_1_2 is // Process each fee. for (uint256 _i; _i < _heldFeesLength; ) { - - if (leftoverAmount == 0) { + if (leftoverAmount == 0) { _heldFeesOf[_projectId].push(_heldFees[_i]); - } else { // Notice here we take feeIn the stored .amount uint256 _feeAmount = ( @@ -1542,7 +1540,6 @@ abstract contract JBPayoutRedemptionPaymentTerminal3_1_2 is } leftoverAmount = 0; } - } unchecked { diff --git a/contracts/abstract/JBPayoutRedemptionPaymentTerminal3_2.sol b/contracts/abstract/JBPayoutRedemptionPaymentTerminal3_2.sol index 5d2fb671a..89b7a04be 100644 --- a/contracts/abstract/JBPayoutRedemptionPaymentTerminal3_2.sol +++ b/contracts/abstract/JBPayoutRedemptionPaymentTerminal3_2.sol @@ -17,7 +17,7 @@ import {IJBPayoutTerminal3_1} from './../interfaces/IJBPayoutTerminal3_1.sol'; import {IJBPrices} from './../interfaces/IJBPrices.sol'; import {IJBProjects} from './../interfaces/IJBProjects.sol'; import {IJBRedemptionTerminal} from './../interfaces/IJBRedemptionTerminal.sol'; -import {IJBSingleTokenPaymentTerminalStore3_1_1} from './../interfaces/IJBSingleTokenPaymentTerminalStore3_1_1.sol'; +import {IJBSingleTokenPaymentTerminalStore3_2} from './../interfaces/IJBSingleTokenPaymentTerminalStore3_2.sol'; import {IJBSplitAllocator} from './../interfaces/IJBSplitAllocator.sol'; import {JBConstants} from './../libraries/JBConstants.sol'; import {JBCurrencies} from './../libraries/JBCurrencies.sol'; @@ -126,19 +126,19 @@ abstract contract JBPayoutRedemptionPaymentTerminal3_2 is uint256 _projectId ) external view virtual override returns (uint256) { // Get this terminal's current overflow. - uint256 _overflow = IJBSingleTokenPaymentTerminalStore3_1_1(store).currentOverflowOf( + uint256 _overflow = IJBSingleTokenPaymentTerminalStore3_2(store).currentOverflowOf( this, _projectId ); // Adjust the decimals of the fixed point number if needed to have 18 decimals. - uint256 _adjustedOverflow = (decimals == 18) + uint256 _adjustedOverflow = decimals == 18 ? _overflow : JBFixedPointNumber.adjustDecimals(_overflow, decimals, 18); // Return the amount converted to ETH. return - (currency == JBCurrencies.ETH) + currency == JBCurrencies.ETH ? _adjustedOverflow : PRBMath.mulDiv( _adjustedOverflow, @@ -229,57 +229,6 @@ abstract contract JBPayoutRedemptionPaymentTerminal3_2 is // ---------------------- external transactions ---------------------- // //*********************************************************************// - /// @notice Contribute tokens to a project. - /// @param _projectId The ID of the project being paid. - /// @param _amount The amount of terminal tokens being received, as a fixed point number with the same amount of decimals as this terminal. If this terminal's token is ETH, this is ignored and msg.value is used in its place. - /// @param _token The token being paid. This terminal ignores this property since it only manages one token. - /// @param _beneficiary The address to mint tokens for and pass along to the funding cycle's data source and delegate. - /// @param _minReturnedTokens The minimum number of project tokens expected in return, as a fixed point number with the same amount of decimals as this terminal. - /// @param _preferClaimedTokens A flag indicating whether the request prefers to mint project tokens into the beneficiaries wallet rather than leaving them unclaimed. This is only possible if the project has an attached token contract. Leaving them unclaimed saves gas. - /// @param _memo A memo to pass along to the emitted event, and passed along the the funding cycle's data source and delegate. A data source can alter the memo before emitting in the event and forwarding to the delegate. - /// @param _metadata Bytes to send along to the data source, delegate, and emitted event, if provided. - /// @return The number of tokens minted for the beneficiary, as a fixed point number with 18 decimals. - function pay( - uint256 _projectId, - uint256 _amount, - address _token, - address _beneficiary, - uint256 _minReturnedTokens, - bool _preferClaimedTokens, - string calldata _memo, - bytes calldata _metadata - ) external payable virtual override returns (uint256) { - _token; // Prevents unused var compiler and natspec complaints. - - // ETH shouldn't be sent if this terminal's token isn't ETH. - if (token != JBTokens.ETH) { - if (msg.value != 0) revert NO_MSG_VALUE_ALLOWED(); - - // Get a reference to the balance before receiving tokens. - uint256 _balanceBefore = _balance(); - - // Transfer tokens to this terminal from the msg sender. - _transferFrom(msg.sender, payable(address(this)), _amount); - - // The amount should reflect the change in balance. - _amount = _balance() - _balanceBefore; - } - // If this terminal's token is ETH, override _amount with msg.value. - else _amount = msg.value; - - return - _pay( - _amount, - msg.sender, - _projectId, - _beneficiary, - _minReturnedTokens, - _preferClaimedTokens, - _memo, - _metadata - ); - } - /// @notice Holders can redeem their tokens to claim the project's overflowed tokens, or to trigger rules determined by the project's current funding cycle's data source. /// @dev Only a token holder or a designated operator can redeem its tokens. /// @param _holder The account to redeem tokens for. @@ -406,7 +355,7 @@ abstract contract JBPayoutRedemptionPaymentTerminal3_2 is if (!_to.acceptsToken(token, _projectId)) revert TERMINAL_TOKENS_INCOMPATIBLE(); // Record the migration in the store. - balance = IJBSingleTokenPaymentTerminalStore3_1_1(store).recordMigration(_projectId); + balance = IJBSingleTokenPaymentTerminalStore3_2(store).recordMigration(_projectId); // Transfer the balance if needed. if (balance != 0) { @@ -514,6 +463,57 @@ abstract contract JBPayoutRedemptionPaymentTerminal3_2 is // ----------------------- public transactions ----------------------- // //*********************************************************************// + /// @notice Contribute tokens to a project. + /// @param _projectId The ID of the project being paid. + /// @param _amount The amount of terminal tokens being received, as a fixed point number with the same amount of decimals as this terminal. If this terminal's token is ETH, this is ignored and msg.value is used in its place. + /// @param _token The token being paid. This terminal ignores this property since it only manages one token. + /// @param _beneficiary The address to mint tokens for and pass along to the funding cycle's data source and delegate. + /// @param _minReturnedTokens The minimum number of project tokens expected in return, as a fixed point number with the same amount of decimals as this terminal. + /// @param _preferClaimedTokens A flag indicating whether the request prefers to mint project tokens into the beneficiaries wallet rather than leaving them unclaimed. This is only possible if the project has an attached token contract. Leaving them unclaimed saves gas. + /// @param _memo A memo to pass along to the emitted event, and passed along the the funding cycle's data source and delegate. A data source can alter the memo before emitting in the event and forwarding to the delegate. + /// @param _metadata Bytes to send along to the data source, delegate, and emitted event, if provided. + /// @return The number of tokens minted for the beneficiary, as a fixed point number with 18 decimals. + function pay( + uint256 _projectId, + uint256 _amount, + address _token, + address _beneficiary, + uint256 _minReturnedTokens, + bool _preferClaimedTokens, + string calldata _memo, + bytes calldata _metadata + ) public payable virtual override returns (uint256) { + _token; // Prevents unused var compiler and natspec complaints. + + // ETH shouldn't be sent if this terminal's token isn't ETH. + if (token != JBTokens.ETH) { + if (msg.value != 0) revert NO_MSG_VALUE_ALLOWED(); + + // Get a reference to the balance before receiving tokens. + uint256 _balanceBefore = _balance(); + + // Transfer tokens to this terminal from the msg sender. + _transferFrom(msg.sender, payable(address(this)), _amount); + + // The amount should reflect the change in balance. + _amount = _balance() - _balanceBefore; + } + // If this terminal's token is ETH, override _amount with msg.value. + else _amount = msg.value; + + return + _pay( + _amount, + msg.sender, + _projectId, + _beneficiary, + _minReturnedTokens, + _preferClaimedTokens, + _memo, + _metadata + ); + } + /// @notice Receives funds belonging to the specified project. /// @param _projectId The ID of the project to which the funds received belong. /// @param _amount The amount of tokens to add, as a fixed point number with the same number of decimals as this terminal. If this is an ETH terminal, this is ignored and msg.value is used instead. @@ -626,7 +626,7 @@ abstract contract JBPayoutRedemptionPaymentTerminal3_2 is reclaimAmount, _delegateAllocations, _memo - ) = IJBSingleTokenPaymentTerminalStore3_1_1(store).recordRedemptionFor( + ) = IJBSingleTokenPaymentTerminalStore3_2(store).recordRedemptionFor( _holder, _projectId, _tokenCount, @@ -780,7 +780,7 @@ abstract contract JBPayoutRedemptionPaymentTerminal3_2 is ( JBFundingCycle memory _fundingCycle, uint256 _distributedAmount - ) = IJBSingleTokenPaymentTerminalStore3_1_1(store).recordDistributionFor( + ) = IJBSingleTokenPaymentTerminalStore3_2(store).recordDistributionFor( _projectId, _amount, _currency @@ -891,7 +891,7 @@ abstract contract JBPayoutRedemptionPaymentTerminal3_2 is ( JBFundingCycle memory _fundingCycle, uint256 _distributedAmount - ) = IJBSingleTokenPaymentTerminalStore3_1_1(store).recordUsedAllowanceOf( + ) = IJBSingleTokenPaymentTerminalStore3_2(store).recordUsedAllowanceOf( _projectId, _amount, _currency @@ -1259,10 +1259,7 @@ abstract contract JBPayoutRedemptionPaymentTerminal3_2 is if (_allowanceAmount != 0) _cancelTransferTo(_expectedDestination, _allowanceAmount); // Add undistributed amount back to project's balance. - IJBSingleTokenPaymentTerminalStore3_1_1(store).recordAddedBalanceFor( - _projectId, - _depositAmount - ); + IJBSingleTokenPaymentTerminalStore3_2(store).recordAddedBalanceFor(_projectId, _depositAmount); } /// @notice Contribute tokens to a project. @@ -1306,7 +1303,7 @@ abstract contract JBPayoutRedemptionPaymentTerminal3_2 is _tokenCount, _delegateAllocations, _memo - ) = IJBSingleTokenPaymentTerminalStore3_1_1(store).recordPaymentFrom( + ) = IJBSingleTokenPaymentTerminalStore3_2(store).recordPaymentFrom( _payer, _bundledAmount, _projectId, @@ -1414,7 +1411,7 @@ abstract contract JBPayoutRedemptionPaymentTerminal3_2 is uint256 _refundedFees = _shouldRefundHeldFees ? _refundHeldFees(_projectId, _amount) : 0; // Record the added funds with any refunded fees. - IJBSingleTokenPaymentTerminalStore3_1_1(store).recordAddedBalanceFor( + IJBSingleTokenPaymentTerminalStore3_2(store).recordAddedBalanceFor( _projectId, _amount + _refundedFees ); diff --git a/contracts/interfaces/IJBPayoutRedemptionPaymentTerminal3_2.sol b/contracts/interfaces/IJBPayoutRedemptionPaymentTerminal3_2.sol index 28db42023..4dac77e88 100644 --- a/contracts/interfaces/IJBPayoutRedemptionPaymentTerminal3_2.sol +++ b/contracts/interfaces/IJBPayoutRedemptionPaymentTerminal3_2.sol @@ -128,7 +128,7 @@ interface IJBPayoutRedemptionPaymentTerminal3_2 is event SetFee(uint256 fee, address caller); - event SetFeeGauge(address indexed feeGauge, address caller); + // event SetFeeGauge(address indexed feeGauge, address caller); event SetFeelessAddress(address indexed addrs, bool indexed flag, address caller); @@ -179,7 +179,7 @@ interface IJBPayoutRedemptionPaymentTerminal3_2 is function fee() external view returns (uint256); - function feeGauge() external view returns (address); + // function feeGauge() external view returns (address); function isFeelessAddress(address account) external view returns (bool); @@ -189,7 +189,7 @@ interface IJBPayoutRedemptionPaymentTerminal3_2 is function setFee(uint256 fee) external; - function setFeeGauge(address feeGauge) external; + // function setFeeGauge(address feeGauge) external; function setFeelessAddress(address account, bool flag) external; } diff --git a/contracts/interfaces/IJBPermit2PaymentTerminal.sol b/contracts/interfaces/IJBPermit2PaymentTerminal.sol new file mode 100644 index 000000000..3e933d566 --- /dev/null +++ b/contracts/interfaces/IJBPermit2PaymentTerminal.sol @@ -0,0 +1,33 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import {IERC165} from '@openzeppelin/contracts/utils/introspection/IERC165.sol'; +import {IPermit2} from 'permit2/src/interfaces/IPermit2.sol'; +import {JBSingleAllowanceData} from '../structs/JBSingleAllowanceData.sol'; +import {IJBPaymentTerminal} from './IJBPaymentTerminal.sol'; + +interface IJBPermit2PaymentTerminal is IJBPaymentTerminal { + function PERMIT2() external returns (IPermit2 _permit2); + + function payAndSetAllowance( + uint256 _projectId, + uint256 _amount, + address _token, + address _beneficiary, + uint256 _minReturnedTokens, + bool _preferClaimedTokens, + string calldata _memo, + bytes calldata _metadata, + JBSingleAllowanceData calldata _allowance + ) external returns (uint256 beneficiaryTokenCount); + + function addToBalanceOfAndSetAllowance( + uint256 _projectId, + uint256 _amount, + address _token, + bool _shouldRefundHeldFees, + string calldata _memo, + bytes calldata _metadata, + JBSingleAllowanceData calldata _allowance + ) external; +} diff --git a/contracts/structs/JBSingleAllowanceData.sol b/contracts/structs/JBSingleAllowanceData.sol new file mode 100644 index 000000000..344795bc2 --- /dev/null +++ b/contracts/structs/JBSingleAllowanceData.sol @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +/// @custom:member sigDeadline deadline on the permit signature +/// @custom:member amount the maximum amount allowed to spend +/// @custom:member expiration timestamp at which a spender's token allowances become invalid +/// @custom:member nonce an incrementing value indexed per owner,token,and spender for each signature +/// @custom:member signature the signature over the permit data. Supports EOA signatures, compact signatures defined by EIP-2098, and contract signatures defined by EIP-1271 +struct JBSingleAllowanceData { + uint256 sigDeadline; + uint160 amount; + uint48 expiration; + uint48 nonce; + bytes signature; +} diff --git a/package.json b/package.json index d1ea23ad7..7fba1251e 100644 --- a/package.json +++ b/package.json @@ -11,8 +11,9 @@ "license": "MIT", "dependencies": { "@chainlink/contracts": "^0.1.6", + "@openzeppelin/contracts": "^4.5.0-rc.0", "@paulrberg/contracts": "^3.4.0", - "@openzeppelin/contracts": "^4.5.0-rc.0" + "permit2": "https://github.com/Uniswap/permit2" }, "devDependencies": { "@defi-wonderland/smock": "^2.2.0", @@ -44,4 +45,4 @@ "compile": "yarn clean && hardhat compile", "pretty": "prettier --write \"./**/*.{js,jsx,json,sol}\"" } -} \ No newline at end of file +} diff --git a/yarn.lock b/yarn.lock index c75e9bfdf..77100a064 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8310,6 +8310,10 @@ performance-now@^2.1.0: resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns= +"permit2@https://github.com/Uniswap/permit2": + version "0.0.0" + resolved "https://github.com/Uniswap/permit2#576f549a7351814f112edcc42f3f8472d1712673" + picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.3: version "2.3.1" resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42"