Skip to content

Commit

Permalink
feat: adding pending message only when it revert
Browse files Browse the repository at this point in the history
  • Loading branch information
wellitongervickas committed Dec 8, 2023
1 parent aa8c544 commit 95e7cf6
Show file tree
Hide file tree
Showing 6 changed files with 105 additions and 29 deletions.
16 changes: 8 additions & 8 deletions contracts-right.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,40 +15,40 @@ pnpm hardhat deploy-bridge-contract --network 43113

=========================

pnpm hardhat deploy-adapter-contract --network 43113 --adapter "CCIPAdapter" --bridge-address 0x82575da60e2dBD70Bf9ED8b87B03D1Dc3208faB3 --router-address 0x554472a2720e5e7d5d3c817529aba05eed5f82d8 --fee-token-name LINK
pnpm hardhat deploy-adapter-contract --network 43113 --adapter "CCIPAdapter" --bridge-address 0x16Ea9dA3B8E4984e47410A999E03A17bBadbc89a --router-address 0x554472a2720e5e7d5d3c817529aba05eed5f82d8 --fee-token-name LINK

# Set chain settings

=========================

pnpm hardhat set-chain-settings --network 43113 --bridge-address 0x82575da60e2dBD70Bf9ED8b87B03D1Dc3208faB3 --evm-chain-id 80001 --non-evm-chain-id 12532609583862916517 --adapter-address 0xCffb30c3183256592afC335423a65e0c569D43A9 ---target-adapter-address 0xa9e05B1C8Cc483eFb03EBaD156Cd00fc87e54C32 --is-enabled true --gas-limit 4000000
pnpm hardhat set-chain-settings --network 43113 --bridge-address 0x16Ea9dA3B8E4984e47410A999E03A17bBadbc89a --evm-chain-id 80001 --non-evm-chain-id 12532609583862916517 --adapter-address 0xB6d40F6c6D068Ed9708d59420c345eCf3E0C977C ---target-adapter-address 0xBa9F52986D0633Ee57B412cA724455A4710cEa00 --is-enabled true --gas-limit 4000000

# Setup bridge adapter roles

==========================

pnpm hardhat setup-bridge-adapter --network 43113 --bridge-address 0x82575da60e2dBD70Bf9ED8b87B03D1Dc3208faB3 --adapter-address 0xCffb30c3183256592afC335423a65e0c569D43A9 --adapter-router-address 0x554472a2720e5e7d5d3c817529aba05eed5f82d8 --router-to-adapter-function-selector ccipReceive ----bridge-to-adapter-function-selector sendMessageUsingERC20 --adapter-contract-name CCIPAdapter
pnpm hardhat setup-bridge-adapter --network 43113 --bridge-address 0x16Ea9dA3B8E4984e47410A999E03A17bBadbc89a --adapter-address 0xB6d40F6c6D068Ed9708d59420c345eCf3E0C977C --adapter-router-address 0x554472a2720e5e7d5d3c817529aba05eed5f82d8 --router-to-adapter-function-selector ccipReceive ----bridge-to-adapter-function-selector sendMessageUsingERC20 --adapter-contract-name CCIPAdapter

# Verify

=========================

pnpm hardhat verify --network 43113 --contract contracts/Bridge.sol:Bridge 0x82575da60e2dBD70Bf9ED8b87B03D1Dc3208faB3 0xA77Bb3B4aC78198208922A6c919921b274be0F9c 43113
pnpm hardhat verify --network 43113 --contract contracts/Bridge.sol:Bridge 0x16Ea9dA3B8E4984e47410A999E03A17bBadbc89a 0xA77Bb3B4aC78198208922A6c919921b274be0F9c 43113

pnpm hardhat verify --network 43113 --contract contracts/adapters/CCIPAdapter.sol:CCIPAdapter 0xCffb30c3183256592afC335423a65e0c569D43A9 0x82575da60e2dBD70Bf9ED8b87B03D1Dc3208faB3 0x554472a2720e5e7d5d3c817529aba05eed5f82d8 0xA77Bb3B4aC78198208922A6c919921b274be0F9c 0x0b9d5D9136855f6FEc3c0993feE6E9CE8a297846
pnpm hardhat verify --network 43113 --contract contracts/adapters/CCIPAdapter.sol:CCIPAdapter 0xB6d40F6c6D068Ed9708d59420c345eCf3E0C977C 0x16Ea9dA3B8E4984e47410A999E03A17bBadbc89a 0x554472a2720e5e7d5d3c817529aba05eed5f82d8 0xA77Bb3B4aC78198208922A6c919921b274be0F9c 0x0b9d5D9136855f6FEc3c0993feE6E9CE8a297846

# Deploy and bridge ERC721 using ERC20 token as fee

=========================
pnpm hardhat bridge-erc721-using-erc20 --network 43113--token-name "Doodle" --token-symbol "DOD" --bridge-address 0x82575da60e2dBD70Bf9ED8b87B03D1Dc3208faB3 --adapter-address 0xCffb30c3183256592afC335423a65e0c569D43A9 --target-network 80001 --fee-token-name LINK
pnpm hardhat bridge-erc721-using-erc20 --network 43113 --token-name "Doodle" --token-symbol "DOD" --bridge-address 0x16Ea9dA3B8E4984e47410A999E03A17bBadbc89a --adapter-address 0xB6d40F6c6D068Ed9708d59420c345eCf3E0C977C --target-network 80001 --fee-token-name LINK

# Execute

==========================
pnpm hardhat execute-message --network 43113 --adapter-address 0xCffb30c3183256592afC335423a65e0c569D43A9
pnpm hardhat execute-message --network 43113 --adapter-address 0xB6d40F6c6D068Ed9708d59420c345eCf3E0C977C

# Bridge existent ERC721 token

===============================

pnpm hardhat bridge-erc721 --network 43113 --token-address 0x59fD265001A751e8ed32274FaFb40103Ed673FaA --token-id 1 --bridge-address 0x82575da60e2dBD70Bf9ED8b87B03D1Dc3208faB3 --adapter-address 0xCffb30c3183256592afC335423a65e0c569D43A9 --target-network 80001 --fee-token-name LINK --origin-chain-evm-id 80001
pnpm hardhat bridge-erc721 --network 43113 --token-address 0x59fD265001A751e8ed32274FaFb40103Ed673FaA --token-id 1 --bridge-address 0x16Ea9dA3B8E4984e47410A999E03A17bBadbc89a --adapter-address 0xB6d40F6c6D068Ed9708d59420c345eCf3E0C977C --target-network 80001 --fee-token-name LINK --origin-chain-evm-id 80001
13 changes: 13 additions & 0 deletions contracts/adapters/BaseAdapter.sol
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,21 @@ abstract contract BaseAdapter is IBaseAdapter, AccessManaged {
emit IBaseAdapter.MessageSent(payload_.toChain, payload_.receiver, payload_.data);
}

/**
* @notice default implementation for sending crosschain you must implement
* your own logic to accept income messages from external resources (e.g. bridge)
*
* @param payload_ message payload
* @param quotedFee_ required fee amount
*/
function _sendMessage(IBaseAdapter.MessageSend memory payload_, uint256 quotedFee_) internal virtual;

/**
* @notice default implementation for receiving crosschain message and send to bridge
* you should implement your own logic to accept income messages from external resources (e.g. router)
*
* @param payload_ message payload
*/
function _receiveMessage(IBaseAdapter.MessageReceive memory payload_) internal virtual {
IBridge(s_bridge).receiveERC721(payload_);
emit IBaseAdapter.MessageReceived(payload_.fromChain, payload_.sender, payload_.data);
Expand Down
70 changes: 55 additions & 15 deletions contracts/adapters/CCIPAdapter.sol
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,13 @@ contract CCIPAdapter is BaseAdapter, CCIPReceiver, AutomationCompatibleInterface
IBaseAdapter.MessageReceive[] private s_pendingMessagesToExecute;
uint256 private s_messagesExecutedCount;

/// @dev automation settings
/// @dev interval in seconds to automation execute messages
uint256 private s_updateInterval = 60;

/// @dev last timestamp when performUpkeep was executed
uint256 private s_lastTimeStampPerformUpkeep;

/// @dev default limit of messages to execute (batch)
uint256 private s_defaultExecutionLimit = 10;

error NoMessagesAvailable();
Expand Down Expand Up @@ -45,6 +49,7 @@ contract CCIPAdapter is BaseAdapter, CCIPReceiver, AutomationCompatibleInterface
return s_defaultExecutionLimit;
}

/// @dev check if there are any messages available to execute
function checkUpkeep(
bytes calldata /* checkData */
) external view override returns (bool upkeepNeeded, bytes memory /* performData */) {
Expand All @@ -58,6 +63,7 @@ contract CCIPAdapter is BaseAdapter, CCIPReceiver, AutomationCompatibleInterface
return (upkeepNeeded, "");
}

/// @dev interface required by Chainlink Automation
function performUpkeep(bytes calldata /* performData */) external override {
if (s_pendingMessagesToExecute.length == 0) revert NoMessagesAvailable();

Expand All @@ -80,10 +86,21 @@ contract CCIPAdapter is BaseAdapter, CCIPReceiver, AutomationCompatibleInterface
return _getFee(uint64(payload_.toChain), evm2AnyMessage);
}

function _getFee(uint64 toChain, Client.EVM2AnyMessage memory evm2AnyMessage) internal view returns (uint256) {
return IRouterClient(getRouter()).getFee(toChain, evm2AnyMessage);
/**
* @notice get fee amount require for sending message using Chainlink CCIP
* @param toChain_ target chain
* @param evm2AnyMessage_ message payload
*/
function _getFee(uint64 toChain_, Client.EVM2AnyMessage memory evm2AnyMessage_) internal view returns (uint256) {
return IRouterClient(getRouter()).getFee(toChain_, evm2AnyMessage_);
}

/**
* @notice build CCIP message payload
* @param receiver_ address of receiver (crosschain adapter)
* @param data_ message payload
* @param gasLimit_ gas limit
*/
function _buildCCIPMessage(
address receiver_,
bytes memory data_,
Expand Down Expand Up @@ -117,13 +134,18 @@ contract CCIPAdapter is BaseAdapter, CCIPReceiver, AutomationCompatibleInterface
_receiveMessage(payload);
}

/**
* @notice set income message as pending to execute, its override default behavior from BaseAdapter
* to allow automation to execute messages in batches (s_defaultExecutionLimit)
* @param payload_ message payload
*/
function _receiveMessage(IBaseAdapter.MessageReceive memory payload_) internal virtual override {
/// @dev: todo, try before set as peding
// try IBridge(getBridge()).receiveERC721(payload_) {
// /** @dev ignore */
// } catch {
_setPendingMessage(payload_);
// }
/// @dev try before set as peding
try IBridge(getBridge()).receiveERC721(payload_) {
/** @dev ignore */
} catch {
_setPendingMessage(payload_);
}

emit IBaseAdapter.MessageReceived(payload_.fromChain, payload_.sender, payload_.data);
}
Expand All @@ -140,6 +162,10 @@ contract CCIPAdapter is BaseAdapter, CCIPReceiver, AutomationCompatibleInterface
return s_pendingMessagesToExecute[index_];
}

/**
* @notice {public} to execute pending messages in batches manually
* @param limitToExecute_ amount of messages to execute (batch)
*/
function executeMessages(uint256 limitToExecute_) public {
if (limitToExecute_ == 0 || s_pendingMessagesToExecute.length == 0) revert NoMessagesAvailable();

Expand All @@ -150,10 +176,11 @@ contract CCIPAdapter is BaseAdapter, CCIPReceiver, AutomationCompatibleInterface
uint256 lastIndex = limit - 1;
uint256 messagesToDelete = limit;

/// @dev execute pending messages
while (limit > 0) {
IBaseAdapter.MessageReceive memory payload = s_pendingMessagesToExecute[lastIndex];

IBridge(getBridge()).receiveERC721(payload);
_receiveMessage(payload);

s_messagesExecutedCount++;

Expand All @@ -164,16 +191,19 @@ contract CCIPAdapter is BaseAdapter, CCIPReceiver, AutomationCompatibleInterface
limit--;
}

/// @dev remove pending messages from the list
while (messagesToDelete > 0) {
s_pendingMessagesToExecute.pop();
messagesToDelete--;
}
}

/// @dev amount of executed messages
function getMessagesExecutedCount() public view returns (uint256) {
return s_messagesExecutedCount;
}

/// @dev amount of pending messages to execute
function getPendingMessagesToExecuteCount() public view returns (uint256) {
return s_pendingMessagesToExecute.length;
}
Expand All @@ -188,15 +218,24 @@ contract CCIPAdapter is BaseAdapter, CCIPReceiver, AutomationCompatibleInterface
IERC20(feeToken()).approve(getRouter(), quotedFee_);
}

/// @dev set token amounts that is required for send the message
uint256[2] memory tokenAmounts_ = [payload_.gasLimit, quotedFee_];

_ccipSend(uint64(payload_.toChain), payload_.receiver, payload_.data, isFeeTokenNative, tokenAmounts_);

emit IBaseAdapter.MessageSent(payload_.toChain, payload_.receiver, payload_.data);
}

/**
* @notice send message using chainlink CCIP
* @param toChain_ target chain
* @param receiver_ receiver address
* @param data_ message payload
* @param isFeeTokenNative is fee token native
* @param tokenAmounts_ token amounts
*/
function _ccipSend(
uint64 toChain,
uint64 toChain_,
address receiver_,
bytes memory data_,
bool isFeeTokenNative,
Expand All @@ -205,11 +244,12 @@ contract CCIPAdapter is BaseAdapter, CCIPReceiver, AutomationCompatibleInterface
IRouterClient router = IRouterClient(getRouter());
Client.EVM2AnyMessage memory evm2AnyMessage = _buildCCIPMessage(receiver_, data_, tokenAmounts_[0]);

if (!isFeeTokenNative) {
router.ccipSend(toChain, evm2AnyMessage);
} else {
if (isFeeTokenNative) {
/// @dev spend native token as fees
router.ccipSend{value: tokenAmounts_[1]}(toChain, evm2AnyMessage);
router.ccipSend{value: tokenAmounts_[1]}(toChain_, evm2AnyMessage);
} else {
/// @dev just send message since we already approved router to spend ERC20 token as fees
router.ccipSend(toChain_, evm2AnyMessage);
}
}
}
19 changes: 19 additions & 0 deletions contracts/interfaces/IBaseAdapter.sol
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,32 @@ interface IBaseAdapter {

event MessageReceived(uint256 fromChain_, address sender_, bytes data_);

/**
* @notice get bridge address that handle income/outcome messages
*/
function getBridge() external view returns (address);

/**
* @notice get fee token address, if zero address it will be set to native token
*/
function feeToken() external view returns (address);

/**
* @notice get fee amount require for sending message
* @param payload_ message payload
*/
function getFee(MessageSend memory payload_) external view returns (uint256);

/**
* @notice send message using Native token
* @param payload_ message payload
*/
function sendMessageUsingNative(MessageSend memory payload_) external payable;

/**
* @notice send message using ERC20 token
* @param payload_ message payload
*/

function sendMessageUsingERC20(MessageSend memory payload_, uint256 amount_) external;
}
2 changes: 1 addition & 1 deletion contracts/mocks/MockBridge.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ contract MockBridge {
bytes data;
}

bool public s_isLocked;
bool public s_isLocked = true;

function lock(bool status_) external {
s_isLocked = status_;
Expand Down
14 changes: 9 additions & 5 deletions test/adapters/ccip/CCIPAdapter.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,7 @@ describe('CCIPAdapter', function () {
it('should set as pending message on receive', async function () {
const [, mockRouterCaller, fromOtherChainAdapter] = await getSigners()

const mockBridgeAddress = '0xEF324FB84e72F098363837dF92C7aFfF46675411'
const { mockBridgeAddress } = await loadFixture(deployMockBridgeFixture)

const { mockCCIPRouterAddress } = await loadFixture(
deployMockCCIPRouterFixture
Expand Down Expand Up @@ -288,7 +288,7 @@ describe('CCIPAdapter', function () {
it('should increment execute messages count on receive', async function () {
const [, mockRouterCaller, fromOtherChainAdapter] = await getSigners()

const mockBridgeAddress = '0xEF324FB84e72F098363837dF92C7aFfF46675411'
const { mockBridgeAddress } = await loadFixture(deployMockBridgeFixture)

const { mockCCIPRouterAddress } = await loadFixture(
deployMockCCIPRouterFixture
Expand Down Expand Up @@ -335,7 +335,7 @@ describe('CCIPAdapter', function () {
it('should emit MessageReceived on receive message', async function () {
const [, mockRouterCaller, fromOtherChainAdapter] = await getSigners()

const mockBridgeAddress = '0xEF324FB84e72F098363837dF92C7aFfF46675411'
const { mockBridgeAddress } = await loadFixture(deployMockBridgeFixture)

const { mockCCIPRouterAddress } = await loadFixture(
deployMockCCIPRouterFixture
Expand Down Expand Up @@ -404,7 +404,7 @@ describe('CCIPAdapter', function () {
it('should revert if get message from a non existen index when list is not empty', async function () {
const [, mockRouterCaller, fromOtherChainAdapter] = await getSigners()

const mockBridgeAddress = '0xEF324FB84e72F098363837dF92C7aFfF46675411'
const { mockBridgeAddress } = await loadFixture(deployMockBridgeFixture)

const { mockCCIPRouterAddress } = await loadFixture(
deployMockCCIPRouterFixture
Expand Down Expand Up @@ -581,7 +581,9 @@ describe('CCIPAdapter', function () {
it('should remove from pending messages after execution', async function () {
const [, mockRouterCaller, fromOtherChainAdapter] = await getSigners()

const { mockBridgeAddress } = await loadFixture(deployMockBridgeFixture)
const { mockBridgeAddress, mockBridge } = await loadFixture(
deployMockBridgeFixture
)

const { mockCCIPRouterAddress } = await loadFixture(
deployMockCCIPRouterFixture
Expand Down Expand Up @@ -616,6 +618,8 @@ describe('CCIPAdapter', function () {
await ccipAdapter.connect(mockRouterCaller).ccipReceive(payload)
await ccipAdapter.connect(mockRouterCaller).ccipReceive(payload)

await mockBridge.lock(false)

await ccipAdapter.executeMessages(1)

await expect(
Expand Down

0 comments on commit 95e7cf6

Please sign in to comment.