diff --git a/contracts/external/interfaces/ICoreDepositWallet.sol b/contracts/external/interfaces/ICoreDepositWallet.sol index b92a4c9e4..5cf1a5ec6 100644 --- a/contracts/external/interfaces/ICoreDepositWallet.sol +++ b/contracts/external/interfaces/ICoreDepositWallet.sol @@ -29,4 +29,12 @@ interface ICoreDepositWallet { * @param destinationDex The destination dex on HyperCore. */ function deposit(uint256 amount, uint32 destinationDex) external; + + /** + * @notice Deposits tokens to credit a specific recipient on Hypercore. + * @param recipient The address receiving the tokens on HyperCore. + * @param amount The amount of tokens being deposited. + * @param destinationDex The destination dex on HyperCore. + */ + function depositFor(address recipient, uint256 amount, uint32 destinationDex) external; } diff --git a/contracts/libraries/HyperCoreLib.sol b/contracts/libraries/HyperCoreLib.sol index 0c5828041..348ca3254 100644 --- a/contracts/libraries/HyperCoreLib.sol +++ b/contracts/libraries/HyperCoreLib.sol @@ -95,14 +95,42 @@ library HyperCoreLib { (uint256 _amountEVMToSend, uint64 _amountCoreToReceive) = maximumEVMSendAmountToAmounts(amountEVM, decimalDiff); if (_amountEVMToSend != 0) { - transferToCore(erc20EVMAddress, erc20CoreIndex, _amountEVMToSend); - // Transfer the tokens from this contract on HyperCore to the `to` address on HyperCore - transferERC20CoreToCore(erc20CoreIndex, to, _amountCoreToReceive); + if (erc20CoreIndex == USDC_CORE_INDEX) { + IERC20(erc20EVMAddress).forceApprove(USDC_CORE_DEPOSIT_WALLET_ADDRESS, _amountEVMToSend); + ICoreDepositWallet(USDC_CORE_DEPOSIT_WALLET_ADDRESS).depositFor(to, _amountEVMToSend, CORE_SPOT_DEX_ID); + } else { + _transferToCoreViaSystemContract(erc20EVMAddress, erc20CoreIndex, _amountEVMToSend); + // Transfer the tokens from this contract on HyperCore to the `to` address on HyperCore + transferERC20CoreToCore(erc20CoreIndex, to, _amountCoreToReceive); + } } return (_amountEVMToSend, _amountCoreToReceive); } + /** + * @notice Activate a user account on HyperCore from HyperEVM. + * @param erc20EVMAddress The address of the ERC20 token on HyperEVM. + * @param erc20CoreIndex The HyperCore index id of the token to transfer. + * @param user The address to activate on HyperCore. + * @param amountEVM The amount to transfer on HyperEVM. + */ + function activateCoreAccountFromEVM( + address erc20EVMAddress, + uint64 erc20CoreIndex, + address user, + uint256 amountEVM + ) internal { + if (erc20CoreIndex == USDC_CORE_INDEX) { + IERC20(erc20EVMAddress).forceApprove(USDC_CORE_DEPOSIT_WALLET_ADDRESS, amountEVM); + ICoreDepositWallet(USDC_CORE_DEPOSIT_WALLET_ADDRESS).depositFor(user, amountEVM, CORE_SPOT_DEX_ID); + } else { + _transferToCoreViaSystemContract(erc20EVMAddress, erc20CoreIndex, amountEVM); + // Transfer 1 wei to user on HyperCore to activate account + transferERC20CoreToCore(erc20CoreIndex, user, 1); + } + } + /** * @notice Bridges `amountEVM` of `erc20` from this address on HyperEVM to this address on HyperCore. * @dev Returns the amount credited on Core in Core units (post conversion). @@ -123,7 +151,12 @@ library HyperCoreLib { (uint256 _amountEVMToSend, uint64 _amountCoreToReceive) = maximumEVMSendAmountToAmounts(amountEVM, decimalDiff); if (_amountEVMToSend != 0) { - transferToCore(erc20EVMAddress, erc20CoreIndex, _amountEVMToSend); + if (erc20CoreIndex == USDC_CORE_INDEX) { + IERC20(erc20EVMAddress).forceApprove(USDC_CORE_DEPOSIT_WALLET_ADDRESS, _amountEVMToSend); + ICoreDepositWallet(USDC_CORE_DEPOSIT_WALLET_ADDRESS).deposit(_amountEVMToSend, CORE_SPOT_DEX_ID); + } else { + _transferToCoreViaSystemContract(erc20EVMAddress, erc20CoreIndex, _amountEVMToSend); + } } return (_amountEVMToSend, _amountCoreToReceive); @@ -143,20 +176,18 @@ library HyperCoreLib { } /** - * @notice Transfers tokens from this contract on HyperEVM to this contract's address on HyperCore + * @notice Transfers tokens from this contract on HyperEVM to this contract's address on HyperCore via the system contract. + * @dev This should only be used for non-USDC tokens. USDC transfers should go through the CoreDepositWallet. * @param erc20EVMAddress The address of the ERC20 token on HyperEVM * @param erc20CoreIndex The HyperCore index id of the token to transfer * @param amountEVMToSend The amount to transfer on HyperEVM */ - function transferToCore(address erc20EVMAddress, uint64 erc20CoreIndex, uint256 amountEVMToSend) internal { - // USDC requires a special transfer to core - if (erc20CoreIndex == USDC_CORE_INDEX) { - IERC20(erc20EVMAddress).forceApprove(USDC_CORE_DEPOSIT_WALLET_ADDRESS, amountEVMToSend); - ICoreDepositWallet(USDC_CORE_DEPOSIT_WALLET_ADDRESS).deposit(amountEVMToSend, CORE_SPOT_DEX_ID); - } else { - // For all other tokens, transfer to the asset bridge address on HyperCore - IERC20(erc20EVMAddress).safeTransfer(toAssetBridgeAddress(erc20CoreIndex), amountEVMToSend); - } + function _transferToCoreViaSystemContract( + address erc20EVMAddress, + uint64 erc20CoreIndex, + uint256 amountEVMToSend + ) internal { + IERC20(erc20EVMAddress).safeTransfer(toAssetBridgeAddress(erc20CoreIndex), amountEVMToSend); } /** diff --git a/contracts/periphery/mintburn/HyperCoreFlowExecutor.sol b/contracts/periphery/mintburn/HyperCoreFlowExecutor.sol index 1b6457836..924ef3abe 100644 --- a/contracts/periphery/mintburn/HyperCoreFlowExecutor.sol +++ b/contracts/periphery/mintburn/HyperCoreFlowExecutor.sol @@ -900,17 +900,8 @@ contract HyperCoreFlowExecutor is AccessControlUpgradeable, AuthorizedFundedFlow // donationBox @ evm -> Handler @ evm donationBox.withdraw(IERC20(fundingToken), evmAmountToSend); - // Handler @ evm -> Handler @ core - HyperCoreLib.transferERC20EVMToSelfOnCore( - fundingToken, - coreTokenInfo.coreIndex, - evmAmountToSend, - coreTokenInfo.tokenInfo.evmExtraWeiDecimals - ); - // The total balance withdrawn from Handler @ Core for this operation is activationFee + amountSent, so we set - // amountSent to 1 wei to only activate the account - // Handler @ core -> finalRecipient @ core - HyperCoreLib.transferERC20CoreToCore(coreTokenInfo.coreIndex, finalRecipient, 1); + + HyperCoreLib.activateCoreAccountFromEVM(fundingToken, coreTokenInfo.coreIndex, finalRecipient, evmAmountToSend); emit SponsoredAccountActivation(quoteNonce, finalRecipient, fundingToken, evmAmountToSend); }