Skip to content

Commit

Permalink
refactor: blacklisted funds logic (#125)
Browse files Browse the repository at this point in the history
Co-authored-by: excaliborr <124819095+excaliborr@users.noreply.github.com>
Co-authored-by: Disco <131301107+0xDiscotech@users.noreply.github.com>
Co-authored-by: excaliborr <excalibor@defi.sucks>
  • Loading branch information
4 people authored Jul 29, 2024
1 parent 601ec75 commit 3bf97c5
Show file tree
Hide file tree
Showing 12 changed files with 421 additions and 89 deletions.
36 changes: 26 additions & 10 deletions src/contracts/L1OpUSDCBridgeAdapter.sol
Original file line number Diff line number Diff line change
Expand Up @@ -260,30 +260,46 @@ contract L1OpUSDCBridgeAdapter is IL1OpUSDCBridgeAdapter, OpUSDCBridgeAdapter {
}

/**
* @notice Receive the message from the other chain and transfer the tokens to the user
* @dev This function should only be called when receiving a message to transfer the tokens
* @notice Receive the message from the other chain and transfer tokens to the user
* @dev This function should only be called when receiving a message to transfer tokens
* @dev If the transfer fails the funds might be recovered by calling withdrawBlacklistedFunds
* @param _user The user to transfer the tokens to
* @param _spender unused parameter on L1, added for maintainability
* @param _spender The address that provided the tokens
* @param _amount The amount of tokens to transfer
*/
// solhint-disable-next-line no-unused-vars
function receiveMessage(address _user, address _spender, uint256 _amount) external override onlyLinkedAdapter {
// Transfer the tokens to the user
try this.attemptTransfer(_user, _amount) {
emit MessageReceived(_user, _amount, MESSENGER);
emit MessageReceived(_spender, _user, _amount, MESSENGER);
} catch {
userBlacklistedFunds[_user] += _amount;
emit MessageFailed(_user, _amount, MESSENGER);
blacklistedFundsDetails[_spender][_user] += _amount;
emit MessageFailed(_spender, _user, _amount, MESSENGER);
}
}

/**
* @notice Receives a message from L2 if the adapter is deprecated and a user is withdrawing blacklisted funds
* @dev If the _spender is still blacklisted, the user will be forced to replay this message
* @param _spender The user that initialy provided the tokens
* @param _amount The amount of tokens to withdraw
*/
function receiveWithdrawBlacklistedFundsPostMigration(address _spender, uint256 _amount) external onlyLinkedAdapter {
if (messengerStatus != Status.Deprecated) revert IOpUSDCBridgeAdapter_NotMigrated();

// If the spender is still blacklisted, the user will be forced to replay this message
IUSDC(USDC).safeTransfer(_spender, _amount);

emit BlacklistedFundsWithdrawn(_spender, _amount);
}

/**
* @notice Withdraws the blacklisted funds from the contract incase they get unblacklisted
* @param _spender The address that provided the tokens
* @param _user The user to withdraw the funds for
*/
function withdrawBlacklistedFunds(address _user) external override {
uint256 _amount = userBlacklistedFunds[_user];
userBlacklistedFunds[_user] = 0;
function withdrawBlacklistedFunds(address _spender, address _user) external override {
uint256 _amount = blacklistedFundsDetails[_spender][_user];
blacklistedFundsDetails[_spender][_user] = 0;

// The check for if the user is blacklisted happens in USDC's contract
IUSDC(USDC).safeTransfer(_user, _amount);
Expand Down
39 changes: 24 additions & 15 deletions src/contracts/L2OpUSDCBridgeAdapter.sol
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,7 @@ contract L2OpUSDCBridgeAdapter is IL2OpUSDCBridgeAdapter, OpUSDCBridgeAdapter {
/**
* @notice Receive the message from the other chain and mint the bridged representation for the user
* @dev This function should only be called when receiving a message to mint the bridged representation
* @dev If the mint fails the funds might be recovered by calling withdrawBlacklistedFunds
* @param _user The user to mint the bridged representation for
* @param _spender The address that provided the tokens
* @param _amount The amount of tokens to mint
Expand All @@ -228,30 +229,38 @@ contract L2OpUSDCBridgeAdapter is IL2OpUSDCBridgeAdapter, OpUSDCBridgeAdapter {
} else {
// Mint the tokens to the user
try IUSDC(USDC).mint(_user, _amount) {
emit MessageReceived(_user, _amount, MESSENGER);
emit MessageReceived(_spender, _user, _amount, MESSENGER);
} catch {
userBlacklistedFunds[_user] += _amount;
emit MessageFailed(_user, _amount, MESSENGER);
blacklistedFundsDetails[_spender][_user] += _amount;
emit MessageFailed(_spender, _user, _amount, MESSENGER);
}
}
}

/**
* @notice Mints the blacklisted funds from the contract incase they get unblacklisted
* @dev Returns the funds to the spender through a message to L1 if the contract is deprecated
* @param _spender The address that provided the tokens
* @param _user The user to withdraw the funds for
*/
function withdrawBlacklistedFunds(address _user) external override {
uint256 _amount = userBlacklistedFunds[_user];
userBlacklistedFunds[_user] = 0;

// NOTE: This will fail after migration as the adapter will no longer be a minter
// All funds need to be recovered from the contract before migration if applicable
// TODO: If migration has happend instead send a message back to L1 to recover the funds

// The check for if the user is blacklisted happens in USDC's contract
IUSDC(USDC).mint(_user, _amount);

emit BlacklistedFundsWithdrawn(_user, _amount);
function withdrawBlacklistedFunds(address _spender, address _user) external override {
uint256 _amount = blacklistedFundsDetails[_spender][_user];
blacklistedFundsDetails[_spender][_user] = 0;

if (messengerStatus != Status.Deprecated) {
// The check for if the user is blacklisted happens in USDC's contract
IUSDC(USDC).mint(_user, _amount);
emit BlacklistedFundsWithdrawn(_user, _amount);
} else {
uint32 _minGasLimit = 150_000;
// Send the message to the linked adapter
ICrossDomainMessenger(MESSENGER).sendMessage(
LINKED_ADAPTER,
abi.encodeCall(IL1OpUSDCBridgeAdapter.receiveWithdrawBlacklistedFundsPostMigration, (_spender, _amount)),
_minGasLimit
);
emit BlacklistedFundsSentBackToL1(_spender, _amount);
}
}

/*///////////////////////////////////////////////////////////////
Expand Down
13 changes: 7 additions & 6 deletions src/contracts/universal/OpUSDCBridgeAdapter.sol
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ abstract contract OpUSDCBridgeAdapter is UUPSUpgradeable, OwnableUpgradeable, EI
mapping(address _user => mapping(uint256 _nonce => bool _used)) public userNonces;

/// @inheritdoc IOpUSDCBridgeAdapter
mapping(address _user => uint256 _blacklistedAmount) public userBlacklistedFunds;
mapping(address _spender => mapping(address _user => uint256 _blacklistedAmount)) public blacklistedFundsDetails;

/**
* @notice Construct the OpUSDCBridgeAdapter contract
Expand Down Expand Up @@ -90,19 +90,20 @@ abstract contract OpUSDCBridgeAdapter is UUPSUpgradeable, OwnableUpgradeable, EI
) external virtual;

/**
* @notice Receive the message from the other chain and mint the bridged representation for the user
* @dev This function should only be called when receiving a message to mint the bridged representation
* @param _user The user to mint the bridged representation for
* @notice Receive the message from the other chain and mint or transfer tokens to the user
* @dev This function should only be called when receiving a message to mint or transfer tokens
* @param _user The user to mint or transfer the tokens for
* @param _spender The address that provided the tokens
* @param _amount The amount of tokens to mint
* @param _amount The amount of tokens to transfer or mint
*/
function receiveMessage(address _user, address _spender, uint256 _amount) external virtual;

/**
* @notice Withdraws the blacklisted funds from the contract if they get unblacklisted
* @param _spender The address that provided the tokens
* @param _user The user to withdraw the funds for
*/
function withdrawBlacklistedFunds(address _user) external virtual;
function withdrawBlacklistedFunds(address _spender, address _user) external virtual;

/**
* @notice Cancels a signature by setting the nonce as used
Expand Down
8 changes: 8 additions & 0 deletions src/interfaces/IL1OpUSDCBridgeAdapter.sol
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,14 @@ interface IL1OpUSDCBridgeAdapter {
*/
function resumeMessaging(uint32 _minGasLimit) external;

/**
* @notice Receives a message from L2 if the adapter is deprecated and a user is withdrawing blacklisted funds
* @dev If the _spender is still blacklisted, the user will be forced to replay this message
* @param _spender The user that initialy provided the tokens
* @param _amount The amount of tokens to withdraw
*/
function receiveWithdrawBlacklistedFundsPostMigration(address _spender, uint256 _amount) external;

/*///////////////////////////////////////////////////////////////
VARIABLES
///////////////////////////////////////////////////////////////*/
Expand Down
1 change: 1 addition & 0 deletions src/interfaces/IL2OpUSDCBridgeAdapter.sol
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ interface IL2OpUSDCBridgeAdapter {
/*///////////////////////////////////////////////////////////////
LOGIC
///////////////////////////////////////////////////////////////*/

/**
* @notice Initiates the process to migrate the bridged USDC to native USDC
* @dev Full migration cant finish until L1 receives the message for setting the burn amount
Expand Down
39 changes: 28 additions & 11 deletions src/interfaces/IOpUSDCBridgeAdapter.sol
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ interface IOpUSDCBridgeAdapter {
Deprecated
}

/*///////////////////////////////////////////////////////////////
STRUCTS
///////////////////////////////////////////////////////////////*/

/**
* @notice The struct to hold the data for a bridge message with signature
* @param to The target address on the destination chain
Expand Down Expand Up @@ -58,11 +62,12 @@ interface IOpUSDCBridgeAdapter {

/**
* @notice Emitted when a message as recieved
* @param _spender The address that provided the tokens
* @param _user The user that recieved the message
* @param _amount The amount of tokens recieved
* @param _messenger The address of the messenger contract that was recieved through
*/
event MessageReceived(address _user, uint256 _amount, address _messenger);
event MessageReceived(address _spender, address _user, uint256 _amount, address _messenger);

/**
* @notice Emitted when messaging is resumed
Expand All @@ -81,11 +86,12 @@ interface IOpUSDCBridgeAdapter {

/**
* @notice Emitted when a message fails
* @param _spender The address that provided the tokens
* @param _user The user that the message failed for
* @param _amount The amount of tokens that were added to the blacklisted funds
* @param _messenger The address of the messenger that the message failed for
*/
event MessageFailed(address _user, uint256 _amount, address _messenger);
event MessageFailed(address _spender, address _user, uint256 _amount, address _messenger);

/**
* @notice Emitted when the blacklisted funds are withdrawn
Expand All @@ -94,9 +100,17 @@ interface IOpUSDCBridgeAdapter {
*/
event BlacklistedFundsWithdrawn(address _user, uint256 _amountWithdrawn);

/**
* @notice Emitted when the blacklisted funds are sent back to L1
* @param _spender The address that provided the tokens
* @param _amountSent The amount of tokens that were withdrawn
*/
event BlacklistedFundsSentBackToL1(address _spender, uint256 _amountSent);

/*///////////////////////////////////////////////////////////////
ERRORS
///////////////////////////////////////////////////////////////*/

/**
* @notice Error when burnLockedUSDC is called before a burn amount is set
*/
Expand Down Expand Up @@ -163,13 +177,14 @@ interface IOpUSDCBridgeAdapter {
error IOpUSDCBridgeAdapter_BlacklistedAddress();

/**
* @notice Error when bridgedUSDC has already been migrated to native USDC
* @notice Error when bridgedUSDC has not been migrated yet to native USDC
*/
error IOpUSDCBridgeAdapter_Migrated();
error IOpUSDCBridgeAdapter_NotMigrated();

/*///////////////////////////////////////////////////////////////
LOGIC
///////////////////////////////////////////////////////////////*/

/**
* @notice Send tokens to other chain through the linked adapter
* @param _to The target address on the destination chain
Expand Down Expand Up @@ -199,19 +214,20 @@ interface IOpUSDCBridgeAdapter {
) external;

/**
* @notice Receive the message from the other chain and mint the bridged representation for the user
* @dev This function should only be called when receiving a message to mint the bridged representation
* @param _user The user to mint the bridged representation for
* @notice Receive the message from the other chain and mint or transfer tokens to the user
* @dev This function should only be called when receiving a message to mint or transfer tokens
* @param _user The user to mint or transfer the tokens for
* @param _spender The address that provided the tokens
* @param _amount The amount of tokens to mint
* @param _amount The amount of tokens to transfer or mint
*/
function receiveMessage(address _user, address _spender, uint256 _amount) external;

/**
* @notice Withdraws the blacklisted funds from the contract if they get unblacklisted
* @param _spender The address that provided the tokens
* @param _user The user to withdraw the funds for
*/
function withdrawBlacklistedFunds(address _user) external;
function withdrawBlacklistedFunds(address _spender, address _user) external;

/**
* @notice Cancels a signature by setting the nonce as used
Expand Down Expand Up @@ -260,8 +276,9 @@ interface IOpUSDCBridgeAdapter {

/**
* @notice Returns the amount of funds locked that got blacklisted for a specific user
* @param _spender The address that provided the tokens
* @param _user The user to check for
* @return _amount The amount of funds locked from blacklisted messages
* @return _blacklistedAmount The amount of funds locked from blacklisted messages
*/
function userBlacklistedFunds(address _user) external view returns (uint256 _amount);
function blacklistedFundsDetails(address _spender, address _user) external view returns (uint256 _blacklistedAmount);
}
2 changes: 2 additions & 0 deletions test/integration/Factories.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,13 @@ contract Integration_Factories is IntegrationBase {
_l2Deployments.usdcInitTxs[0] = abi.encodeWithSignature('initializeV2(string)', 'Bridged USDC (Optimism)');

// Deploy the contracts
uint256 _deploymentsSaltCounter = l1Factory.deploymentsSaltCounter();
vm.prank(_user);
(address _l1Adapter, address _l2Factory, address _l2Adapter) =
l1Factory.deploy(address(OPTIMISM_L1_MESSENGER), _owner, 'Optimism', _l2Deployments);

// Check the adapter was properly deployed on L1
assertEq(l1Factory.deploymentsSaltCounter(), _deploymentsSaltCounter + 2);
assertEq(IOpUSDCBridgeAdapter(_l1Adapter).USDC(), address(MAINNET_USDC), '1');
assertEq(IOpUSDCBridgeAdapter(_l1Adapter).MESSENGER(), address(OPTIMISM_L1_MESSENGER), '2');
assertEq(IOpUSDCBridgeAdapter(_l1Adapter).LINKED_ADAPTER(), _l2Adapter, '3');
Expand Down
Loading

0 comments on commit 3bf97c5

Please sign in to comment.