Skip to content

Commit

Permalink
feat: specs updated
Browse files Browse the repository at this point in the history
  • Loading branch information
wellitongervickas committed Dec 3, 2023
1 parent de2705a commit 624902b
Show file tree
Hide file tree
Showing 6 changed files with 42 additions and 46 deletions.
45 changes: 27 additions & 18 deletions contracts/Bridge.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {IBridge} from "./interfaces/IBridge.sol";
import {IERC721, IERC721Metadata, IERC721Receiver} from "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import {WERC721} from "./wrapped/WERC721.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "hardhat/console.sol";

contract Bridge is IBridge, AccessManaged {
uint256 private immutable s_chainId;
Expand All @@ -17,8 +18,12 @@ contract Bridge is IBridge, AccessManaged {
/// @dev nonEvmChainId => evmChainId
mapping(uint256 => uint256) private s_nonEvmChains;

/// @dev originAddress -> wrapped token
mapping(address => IBridge.ERC721Wrapped) private s_wrappedERC721Tokens;

/// @dev wrapped token address -> origin address
mapping(address => address) private s_wrappedERC721TokenOrigin;

// mapping(uint256 => IBridge.ERC721Receive) public receivedERC721;
// uint256 public receivedERC721Count;

Expand Down Expand Up @@ -91,6 +96,8 @@ contract Bridge is IBridge, AccessManaged {
originAddress: originAddress,
wrappedAddress: wrappedAddress_
});

s_wrappedERC721TokenOrigin[wrappedAddress_] = originAddress;
}

/// @inheritdoc IBridge
Expand All @@ -110,18 +117,20 @@ contract Bridge is IBridge, AccessManaged {
IBridge.ERC721Send memory payload = _getPayload(toChain_, token_, tokenId_);
if (adapter.getFee(payload) > amount_) revert IBridge.InsufficientFeeTokenAmount();

/// @dev get fees tokens first
IERC20(adapter.feeToken()).transferFrom(msg.sender, address(this), amount_);

/// @dev check if its wrapped, then burn instead of transfer
if (s_wrappedERC721Tokens[token_].wrappedAddress != address(0)) {
WERC721(token_).burn(tokenId_);
address incomeWrappedTokenAddress = s_wrappedERC721Tokens[s_wrappedERC721TokenOrigin[token_]].wrappedAddress;

if (incomeWrappedTokenAddress != address(0)) {
WERC721(incomeWrappedTokenAddress).safeTransferFrom(msg.sender, address(this), tokenId_);
WERC721(incomeWrappedTokenAddress).burn(tokenId_);
} else {
/// @dev transfer to bridge contract to lock
IERC721(token_).safeTransferFrom(msg.sender, address(this), tokenId_);
}

/// @dev get tokens first
IERC20(adapter.feeToken()).transferFrom(msg.sender, address(this), amount_);

/// @dev approve adapter to spend tokens
/// @dev approve adapter to spend fees tokens
IERC20(adapter.feeToken()).approve(address(adapter), amount_);

adapter.sendMessageUsingERC20(payload, amount_);
Expand All @@ -147,8 +156,11 @@ contract Bridge is IBridge, AccessManaged {
if (adapter.getFee(payload) > msg.value) revert IBridge.InsufficientFeeTokenAmount();

/// @dev check if its wrapped, then burn instead of transfer
if (s_wrappedERC721Tokens[token_].wrappedAddress != address(0)) {
WERC721(token_).burn(tokenId_);
address incomeWrappedTokenAddress = s_wrappedERC721Tokens[s_wrappedERC721TokenOrigin[token_]].wrappedAddress;

if (incomeWrappedTokenAddress != address(0)) {
WERC721(incomeWrappedTokenAddress).safeTransferFrom(msg.sender, address(this), tokenId_);
WERC721(incomeWrappedTokenAddress).burn(tokenId_);
} else {
/// @dev transfer to bridge contract to lock
IERC721(token_).safeTransferFrom(msg.sender, address(this), tokenId_);
Expand Down Expand Up @@ -189,6 +201,7 @@ contract Bridge is IBridge, AccessManaged {
return abi.encode(receiver_, token_, metadata_);
}

/// @dev todo: split this operation to handle by automation instead
/// @inheritdoc IBridge
function receiveERC721(
IBridge.ERC721Receive memory payload_
Expand All @@ -213,20 +226,21 @@ contract Bridge is IBridge, AccessManaged {
IERC721(wrappedERC721Token).safeTransferFrom(address(this), data.receiver, token.tokenId);
} else {
IBridge.ERC721Metadata memory metadata = _getDecodedERC721Metadata(data.metadata);
address wrappedERC721TokenAddress = s_wrappedERC721Tokens[token.tokenAddress].wrappedAddress;
address wrappedERC721Token_ = s_wrappedERC721Tokens[token.tokenAddress].wrappedAddress;

if (wrappedERC721TokenAddress == address(0)) {
if (wrappedERC721Token_ == address(0)) {
/// @dev create new ERC721
wrappedERC721Token = _createWrapped(payload_, token.tokenAddress, metadata.name, metadata.symbol);
_setERC721WrappedToken(wrappedERC721Token, s_nonEvmChains[payload_.fromChain], token.tokenAddress);
} else {
/// @dev reuse an already wrapped ERC721
wrappedERC721Token = wrappedERC721TokenAddress;
wrappedERC721Token = wrappedERC721Token_;
}

WERC721(wrappedERC721Token).safeMint(data.receiver, token.tokenId, metadata.tokenURI);
}

emit IBridge.ERC721WrappedCreated(evmChainId, wrappedERC721Token, token.tokenAddress);
emit IBridge.ERC721WrappedCreated(evmChainId, token.tokenAddress, wrappedERC721Token);
}

function _getDecodedERC721Data(bytes memory data_) internal pure returns (IBridge.ERC721Data memory) {
Expand Down Expand Up @@ -256,13 +270,8 @@ contract Bridge is IBridge, AccessManaged {
string memory name_,
string memory symbol_
) private returns (address wrappedERC721Token) {
/// @dev get salt to deploy same address in any evm chain

bytes32 salt = keccak256(abi.encodePacked(s_nonEvmChains[payload_.fromChain], token));

wrappedERC721Token = address(new WERC721{salt: salt}(address(this), name_, symbol_));

_setERC721WrappedToken(wrappedERC721Token, s_nonEvmChains[payload_.fromChain], token);
}

/// @inheritdoc IBridge
Expand Down
7 changes: 4 additions & 3 deletions contracts/adapters/BaseAdapter.sol
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,11 @@ import {IBaseAdapter} from "../interfaces/IBaseAdapter.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol";

abstract contract BaseAdapter is IBaseAdapter, AccessManaged {
/// @dev bridge address set once in constructor
address private immutable s_bridge;
address private immutable s_feeToken;

constructor(address bridge_, address accessManagement_) AccessManaged(accessManagement_) {
constructor(address bridge_, address accessManagement_, address feeToken_) AccessManaged(accessManagement_) {
s_feeToken = feeToken_;
s_bridge = bridge_;
}

Expand All @@ -27,7 +28,7 @@ abstract contract BaseAdapter is IBaseAdapter, AccessManaged {

/// @inheritdoc IBaseAdapter
function feeToken() public view virtual override returns (address) {
return address(0);
return s_feeToken;
}

/// @inheritdoc IBaseAdapter
Expand Down
10 changes: 1 addition & 9 deletions contracts/adapters/CCIPAdapter.sol
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,12 @@ import {IBridge} from "../interfaces/IBridge.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol";

contract CCIPAdapter is BaseAdapter, CCIPReceiver {
address private immutable s_feeToken;

constructor(
address bridge_,
address accessManagement_,
address router_,
address feeToken_
) BaseAdapter(bridge_, accessManagement_) CCIPReceiver(router_) {
s_feeToken = feeToken_;
}
) BaseAdapter(bridge_, accessManagement_, feeToken_) CCIPReceiver(router_) {}

/// @inheritdoc IBaseAdapter
function getFee(IBridge.ERC721Send memory payload_) public view override returns (uint256) {
Expand Down Expand Up @@ -53,10 +49,6 @@ contract CCIPAdapter is BaseAdapter, CCIPReceiver {
});
}

function feeToken() public view override returns (address) {
return s_feeToken;
}

/// @inheritdoc IBaseAdapter
function router() public view override returns (address) {
return getRouter();
Expand Down
2 changes: 0 additions & 2 deletions tasks/bridge-erc721-using-erc20.ts
Original file line number Diff line number Diff line change
Expand Up @@ -134,8 +134,6 @@ task('bridge-erc721-using-erc20', 'bridge ERC721 contract using erc20 token')
)
}

console.log(`ℹ️ Payload: ${JSON.stringify(payload)}`)

const fee = await adapter.getFee(payload)

console.log('ℹ️ Required feee:', fee)
Expand Down
10 changes: 0 additions & 10 deletions test/adapters/ccip/CCIPAdapter.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -239,11 +239,6 @@ describe('CCIPAdapter', function () {
BRIDGE_ROLE
)

console.log(
'native',
ccipAdapter.interface.getFunction('sendMessageUsingNative').selector
)

const expectedAmount = 200_000
await mockCCIPRouter.setFee(expectedAmount)

Expand Down Expand Up @@ -289,11 +284,6 @@ describe('CCIPAdapter', function () {
BRIDGE_ROLE
)

console.log(
'erc20',
ccipAdapter.interface.getFunction('sendMessageUsingERC20').selector
)

const expectedAmount = 200_000n
await mockCCIPRouter.setFee(expectedAmount)

Expand Down
14 changes: 10 additions & 4 deletions test/bridge/Bridge.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -302,22 +302,28 @@ describe('Bridge', function () {
const receipt = await tx.wait()
const filter = bridge.filters.ERC721WrappedCreated
const logs = await bridge.queryFilter(filter, receipt?.blockHash)

const [, , wrappedTokenAddress] = logs[0].args

const wrappedToken = await ethers.getContractAt(
'ERC721',
'WERC721',
wrappedTokenAddress
)

await wrappedToken.approve(bridgeAddress, tokenId)
await bridge.sendERC721UsingNative(

const tx2 = await bridge.sendERC721UsingNative(
evmChainId,
wrappedTokenAddress,
tokenId
)

const balanceOfERC721 = await mockERC721.balanceOf(currentOwner.address)
expect(balanceOfERC721).to.be.equal(0)
await tx2.wait()

await expect(wrappedToken.ownerOf(tokenId)).to.be.revertedWithCustomError(
wrappedToken,
'ERC721NonexistentToken'
)
})

it('should emit event on transfer ERC721 to bridge contract', async function () {
Expand Down

0 comments on commit 624902b

Please sign in to comment.