From 63845842d20e1ac5c817dd215f3d1409913cabf8 Mon Sep 17 00:00:00 2001 From: welliton gervickas Date: Mon, 20 Nov 2023 09:33:11 -0300 Subject: [PATCH] fix: transfer issues --- contracts/Bridge.sol | 34 +++++++-------- contracts/adapters/BaseAdapter.sol | 2 +- contracts/interfaces/IBridge.sol | 12 +++--- contracts/mocks/MockBridge.sol | 2 +- test/bridge/Bridge.spec.ts | 67 ++++++++++++++++-------------- 5 files changed, 61 insertions(+), 56 deletions(-) diff --git a/contracts/Bridge.sol b/contracts/Bridge.sol index 1a5602b..c276fb0 100644 --- a/contracts/Bridge.sol +++ b/contracts/Bridge.sol @@ -4,10 +4,10 @@ pragma solidity 0.8.21; import {AccessManaged} from "@openzeppelin/contracts/access/manager/AccessManaged.sol"; import {IBaseAdapter} from "./interfaces/IBaseAdapter.sol"; import {IBridge} from "./interfaces/IBridge.sol"; -import {IERC721, IERC721Receiver} from "@openzeppelin/contracts/token/ERC721/ERC721.sol"; +import {ERC721, IERC721, IERC721Receiver} from "@openzeppelin/contracts/token/ERC721/ERC721.sol"; contract Bridge is IBridge, AccessManaged { - /// @dev nativeChainId => adapterChainId => adapter + /// @dev nativeChainId => chainId => adapter mapping(uint256 => IBridge.AdapterSettings) public s_adapters; constructor(address accessManagement_) AccessManaged(accessManagement_) {} @@ -20,10 +20,10 @@ contract Bridge is IBridge, AccessManaged { } /// @inheritdoc IBridge - function setAdapter(uint256 nativeChainId_, uint256 adapterChainId_, address adapter_) external restricted { - s_adapters[nativeChainId_] = IBridge.AdapterSettings({adapterChainId: adapterChainId_, adapter: adapter_}); + function setAdapter(uint256 nativeChainId_, uint256 chainId_, address adapter_) external restricted { + s_adapters[nativeChainId_] = IBridge.AdapterSettings({chainId: chainId_, adapter: adapter_}); - emit IBridge.AdapterSet(nativeChainId_, adapterChainId_, adapter_); + emit IBridge.AdapterSet(nativeChainId_, chainId_, adapter_); } /// @inheritdoc IBridge @@ -32,32 +32,32 @@ contract Bridge is IBridge, AccessManaged { } /// @inheritdoc IBridge - function transferToChain( + function transferERC721( uint256 toChain_, address receiver_, address token_, uint256 tokenId_ ) external payable checkAdapter(toChain_) { AdapterSettings memory chainAdapter = adapters(toChain_); - address adapter = chainAdapter.adapter; - /// todo: encode baseURI and other data aswell - bytes memory data = abi.encode(token_, tokenId_); + IBaseAdapter adapter = IBaseAdapter(chainAdapter.adapter); - IBridge.MessageSend memory payload = IBridge.MessageSend({ - toChain: chainAdapter.adapterChainId, - receiver: receiver_, - data: data - }); + uint256 chainId = chainAdapter.chainId; - uint256 quotedFees = IBaseAdapter(adapter).getFee(payload); + ERC721 token = ERC721(token_); + + bytes memory data = abi.encode(token_, tokenId_, token.name(), token.symbol(), token.tokenURI(tokenId_)); + + IBridge.MessageSend memory payload = IBridge.MessageSend({toChain: chainId, receiver: receiver_, data: data}); + + uint256 quotedFees = adapter.getFee(payload); if (quotedFees > msg.value) { revert IBridge.InsufficientFeeTokenAmount(); } IERC721(token_).safeTransferFrom(msg.sender, address(this), tokenId_); - IBaseAdapter(adapter).sendMessage(payload); + adapter.sendMessage(payload); emit IBridge.MessageSent(payload.toChain, payload.receiver, payload.data); } @@ -67,7 +67,7 @@ contract Bridge is IBridge, AccessManaged { /// todo: set wrapped asset or create wrapped on lock /// @inheritdoc IBridge /// @dev only adapter can call - function receiveFromChain(IBridge.MessageReceive memory payload_) external override restricted { + function commitOffRamp(IBridge.MessageReceive memory payload_) external override restricted { emit IBridge.MessageReceived(payload_.fromChain, payload_.sender, payload_.data); } diff --git a/contracts/adapters/BaseAdapter.sol b/contracts/adapters/BaseAdapter.sol index 9a0e38f..25671d6 100644 --- a/contracts/adapters/BaseAdapter.sol +++ b/contracts/adapters/BaseAdapter.sol @@ -54,7 +54,7 @@ abstract contract BaseAdapter is IBaseAdapter, AccessManaged { * @param payload_ data to send to bridge */ function _receiveMessage(IBridge.MessageReceive memory payload_) internal virtual { - IBridge(s_bridge).receiveFromChain(payload_); + IBridge(s_bridge).commitOffRamp(payload_); emit IBaseAdapter.MessageReceived(payload_.fromChain, payload_.sender, payload_.data); } diff --git a/contracts/interfaces/IBridge.sol b/contracts/interfaces/IBridge.sol index 8479d64..9b88495 100644 --- a/contracts/interfaces/IBridge.sol +++ b/contracts/interfaces/IBridge.sol @@ -3,7 +3,7 @@ pragma solidity 0.8.21; interface IBridge { struct AdapterSettings { - uint256 adapterChainId; + uint256 chainId; address adapter; } @@ -29,7 +29,7 @@ interface IBridge { error AdapterNotFound(uint256 nativeChainId_); /// @dev Emitted when adapter is changed - event AdapterSet(uint256 indexed nativeChainId_, uint256 indexed adapterChainId_, address adapter_); + event AdapterSet(uint256 indexed nativeChainId_, uint256 indexed chainId_, address adapter_); /// @dev Emitted when message is sent event MessageSent(uint256 toChain, address receiver, bytes data); @@ -40,10 +40,10 @@ interface IBridge { /** * @notice set adapter address from native chainId and abstracted chainId * @param nativeChainId_ native chain id - * @param adapterChainId_ abstracted chain id + * @param chainId_ abstracted chain id * @param adapter_ address of adapter */ - function setAdapter(uint256 nativeChainId_, uint256 adapterChainId_, address adapter_) external; + function setAdapter(uint256 nativeChainId_, uint256 chainId_, address adapter_) external; /** * @notice get adapter address by native chainId @@ -59,7 +59,7 @@ interface IBridge { * @param token_ token address of collection * @param tokenId_ token id to transfer */ - function transferToChain(uint256 toChain_, address receiver_, address token_, uint256 tokenId_) external payable; + function transferERC721(uint256 toChain_, address receiver_, address token_, uint256 tokenId_) external payable; /** * @notice receive NFT transfers @@ -71,5 +71,5 @@ interface IBridge { * @notice receive message from adapter * @param payload_ data received from adapter */ - function receiveFromChain(IBridge.MessageReceive memory payload_) external; + function commitOffRamp(IBridge.MessageReceive memory payload_) external; } diff --git a/contracts/mocks/MockBridge.sol b/contracts/mocks/MockBridge.sol index fdd3ab9..564b3d3 100644 --- a/contracts/mocks/MockBridge.sol +++ b/contracts/mocks/MockBridge.sol @@ -10,7 +10,7 @@ contract MockBridge { event MessageReceived(MessageReceive indexed message_); - function receiveFromChain(MessageReceive memory calldata_) external { + function commitOffRamp(MessageReceive memory calldata_) external { emit MessageReceived(calldata_); } } diff --git a/test/bridge/Bridge.spec.ts b/test/bridge/Bridge.spec.ts index 3a19af4..772d0ed 100644 --- a/test/bridge/Bridge.spec.ts +++ b/test/bridge/Bridge.spec.ts @@ -33,12 +33,10 @@ describe('Bridge', function () { ) const nativeChainId = 137 - const adapterChainId = 80_001 + const chainId = 80_001 await expect( - bridge - .connect(unknown) - .setAdapter(nativeChainId, adapterChainId, adapterAddress) + bridge.connect(unknown).setAdapter(nativeChainId, chainId, adapterAddress) ).to.be.revertedWithCustomError(bridge, 'AccessManagedUnauthorized') }) @@ -50,14 +48,14 @@ describe('Bridge', function () { ) const nativeChainId = 137 - const adapterChainId = 80_001 + const chainId = 80_001 - await bridge.setAdapter(nativeChainId, adapterChainId, adapterAddress) + await bridge.setAdapter(nativeChainId, chainId, adapterAddress) const adapter = await bridge.adapters(nativeChainId) - expect([adapter.adapterChainId, adapter.adapter]).to.deep.equal([ - adapterChainId, + expect([adapter.chainId, adapter.adapter]).to.deep.equal([ + chainId, adapterAddress ]) }) @@ -70,13 +68,11 @@ describe('Bridge', function () { ) const nativeChainId = 137 - const adapterChainId = 80_001 + const chainId = 80_001 - await expect( - bridge.setAdapter(nativeChainId, adapterChainId, adapterAddress) - ) + await expect(bridge.setAdapter(nativeChainId, chainId, adapterAddress)) .to.emit(bridge, 'AdapterSet') - .withArgs(nativeChainId, adapterChainId, adapterAddress) + .withArgs(nativeChainId, chainId, adapterAddress) }) it('should revert if chain does not have any adapter', async function () { @@ -90,7 +86,7 @@ describe('Bridge', function () { const nativeChainId = 137 await expect( - bridge.transferToChain( + bridge.transferERC721( nativeChainId, receiver.address, fakeNFTAddress, @@ -100,32 +96,34 @@ describe('Bridge', function () { }) it('should revert if the amount sent as fee token is insufficient', async function () { - const fakeNFTAddress = ethers.ZeroAddress - const fakeNFTTokenId = 0 + const { mockNFTAddress, mockNFT } = await loadFixture(deployMockNFTFixture) const [receiver] = await getSigners() - const { bridge } = await loadFixture( + const { bridge, bridgeAddress } = await loadFixture( deployBridgeFixture.bind(this, accessManagementAddress) ) const nativeChainId = 137 - const adapterChainId = 12334124515 + const chainId = 12334124515 const { mockAdapterAddress, mockAdapter } = await loadFixture( deployMockAdapterFixture ) await mockAdapter.setFee(200_000) + await bridge.setAdapter(nativeChainId, chainId, mockAdapterAddress) - await bridge.setAdapter(nativeChainId, adapterChainId, mockAdapterAddress) + const tokenId = 1 + await mockNFT.mint(tokenId) + await mockNFT.approve(bridgeAddress, tokenId) await expect( - bridge.transferToChain( + bridge.transferERC721( nativeChainId, receiver.address, - fakeNFTAddress, - fakeNFTTokenId + mockNFTAddress, + tokenId ) ).to.be.revertedWithCustomError(bridge, 'InsufficientFeeTokenAmount') }) @@ -140,17 +138,17 @@ describe('Bridge', function () { ) const nativeChainId = 137 - const adapterChainId = 12334124515 + const chainId = 12334124515 const { mockAdapterAddress } = await loadFixture(deployMockAdapterFixture) - await bridge.setAdapter(nativeChainId, adapterChainId, mockAdapterAddress) + await bridge.setAdapter(nativeChainId, chainId, mockAdapterAddress) const tokenId = 1 await mockNFT.mint(tokenId) await mockNFT.approve(bridgeAddress, tokenId) - await bridge.transferToChain( + await bridge.transferERC721( nativeChainId, receiver.address, mockNFTAddress, @@ -171,23 +169,30 @@ describe('Bridge', function () { ) const nativeChainId = 137 - const adapterChainId = 12334124515 + const chainId = 12334124515 const { mockAdapterAddress } = await loadFixture(deployMockAdapterFixture) - await bridge.setAdapter(nativeChainId, adapterChainId, mockAdapterAddress) + await bridge.setAdapter(nativeChainId, chainId, mockAdapterAddress) const tokenId = 1 await mockNFT.mint(tokenId) await mockNFT.approve(bridgeAddress, tokenId) + // , 'string', 'string', 'string' const encodedData = abiCoder.encode( - ['address', 'uint256'], - [mockNFTAddress, tokenId] + ['address', 'uint256', 'string', 'string', 'string'], + [ + mockNFTAddress, + tokenId, + await mockNFT.name(), + await mockNFT.symbol(), + await mockNFT.tokenURI(tokenId) + ] ) await expect( - bridge.transferToChain( + bridge.transferERC721( nativeChainId, receiver.address, mockNFTAddress, @@ -195,7 +200,7 @@ describe('Bridge', function () { ) ) .to.emit(bridge, 'MessageSent') - .withArgs(adapterChainId, receiver.address, encodedData) + .withArgs(chainId, receiver.address, encodedData) }) it('should revert if call safe transfer from another contract', async function () {