Skip to content

Commit 7d169fd

Browse files
committed
First draft*
0 parents  commit 7d169fd

20 files changed

+883
-0
lines changed

.gitignore

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# Compiler files
2+
cache/
3+
out/
4+
5+
# Ignores development broadcast logs
6+
!/broadcast
7+
/broadcast/*/31337/
8+
/broadcast/**/dry-run/
9+
10+
# Docs
11+
docs/
12+
13+
# Dotenv file
14+
.env
15+
16+
.vscode
17+
/node_modules
18+
bin/

.gitmodules

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
[submodule "lib/openzeppelin-contracts"]
2+
path = lib/openzeppelin-contracts
3+
url = https://github.com/OpenZeppelin/openzeppelin-contracts
4+
[submodule "lib/ccip"]
5+
path = lib/ccip
6+
url = https://github.com/smartcontractkit/ccip

foundry.toml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
[profile.default]
2+
solc = "0.8.20"
3+
src = "src"
4+
out = "out"
5+
libs = ["lib"]
6+
optimizer = true
7+
optimizer_runs = 200
8+
evm_version = 'london'
9+
# See more config options https://github.com/foundry-rs/foundry/tree/master/config

lib/ccip

Submodule ccip added at a759660

lib/openzeppelin-contracts

Submodule openzeppelin-contracts added at 141c947

package.json

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
{
2+
"name": "tg-bridge-contract-solidity",
3+
"version": "1.0.0",
4+
"description": "Bridge contract in Solidity",
5+
"main": "index.js",
6+
"directories": {
7+
"lib": "lib",
8+
"test": "test"
9+
},
10+
"scripts": {
11+
"test": "echo \"Error: no test specified\" && exit 1"
12+
},
13+
"repository": {
14+
"type": "git",
15+
"url": "git+https://github.com/taurusgroup/tg-bridge-contract-solidity.git"
16+
},
17+
"author": "",
18+
"license": "ISC",
19+
"bugs": {
20+
"url": "https://github.com/taurusgroup/tg-bridge-contract-solidity/issues"
21+
},
22+
"homepage": "https://github.com/taurusgroup/tg-bridge-contract-solidity#readme",
23+
"devDependencies": {
24+
"slither": "^0.2.2",
25+
"sol2uml": "^2.5.16",
26+
"surya": "^0.4.6"
27+
}
28+
}

remappings.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
openzeppelin-contracts/=lib/openzeppelin-contracts/contracts
2+
ccip/=lib/ccip/contracts/src/v0.8/ccip
3+
ccip-v08/=lib/ccip/contracts/src/v0.8/
4+
ds-test/=lib/forge-std/lib/ds-test/src/
5+
erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/
6+
forge-std/=lib/forge-std/src/
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// SPDX-License-Identifier: UNLICENSED
2+
3+
pragma solidity ^0.8.0;
4+
5+
interface BridgeVaultInterface {
6+
error BridgeVault_tokenNoBridgeable();
7+
error BridgeVault_AddressZeroNotAllowed();
8+
// by the token holder
9+
event Deposit(address indexed receiverBlockchainDestination, address indexed sourceContract, address indexed destinationContract, uint256 value);
10+
event Withdraw(address indexed sender, address indexed receiverBlockchainSource, address indexed sourceContract, uint256 value);
11+
// By the validator
12+
event Mint(address indexed receiver, address indexed sourceContract, uint256 value);
13+
event Unlock(address indexed sender, address indexed sourceContract, address indexed destinationContract, uint256 value);
14+
//event Burn(address indexed receiver, address indexed sourceContract, uint256 value);
15+
16+
event NewWrapperContract(address indexed sourceContract, address indexed wrapperContract);
17+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
// SPDX-License-Identifier: MIT
2+
3+
pragma solidity ^0.8.20;
4+
5+
import "../../../lib/openzeppelin-contracts/contracts/access/AccessControl.sol";
6+
7+
8+
abstract contract AuthorizationModule is AccessControl{
9+
// MintModule
10+
bytes32 public constant VALIDATOR_ROLE = keccak256("VALIDATOR_ROLE");
11+
// PauseModule
12+
bytes32 public constant PAUSER_ROLE = keccak256("PAUSER_ROLE");
13+
14+
15+
/*
16+
* @dev Returns `true` if `account` has been granted `role`.
17+
*/
18+
function hasRole(
19+
bytes32 role,
20+
address account
21+
) public view virtual override(AccessControl) returns (bool) {
22+
// The Default Admin has all roles
23+
if (AccessControl.hasRole(DEFAULT_ADMIN_ROLE, account)) {
24+
return true;
25+
}
26+
return AccessControl.hasRole(role, account);
27+
}
28+
29+
function supportsInterface(bytes4 interfaceId) public pure virtual override(AccessControl)
30+
returns (bool){
31+
return interfaceId == type(IAccessControl).interfaceId;
32+
33+
}
34+
35+
uint256[50] private __gap;
36+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// SPDX-License-Identifier: MIT
2+
3+
pragma solidity ^0.8.20;
4+
5+
library CCIPErrors {
6+
// Custom errors to provide more descriptive revert messages.
7+
error CCIP_NotEnoughBalance(uint256 currentBalance, uint256 calculatedFees); // Used to make sure contract has enough balance.
8+
// Used when the destination chain has not been allowlisted by the contract owner.
9+
error CCIP_CCIPAllowListedChain_DestinationChainNotAllowlisted(uint64 destinationChainSelector);
10+
// Used when the source chain has not been allowlisted by the contract owner.
11+
error CCIP_CCIPAllowListedChain_SourceChainNotAllowlisted(uint64 sourceChainSelector);
12+
13+
14+
// CCIPBaseReceiverDefensive
15+
error CCIP_CCIPReceiverDefensiveNotRightSender();
16+
17+
error NothingToWithdraw(); // Used when trying to withdraw Ether but there's nothing to withdraw.
18+
error FailedToWithdrawEth(address owner, address target, uint256 value); // Used when the withdrawal of Ether fails.
19+
error DestinationChainNotAllowlisted(uint64 destinationChainSelector); // Used when the destination chain has not been allowlisted by the contract owner.
20+
error SourceChainNotAllowed(uint64 sourceChainSelector); // Used when the source chain has not been allowlisted by the contract owner.
21+
error SenderNotAllowed(address sender); // Used when the sender has not been allowlisted by the contract owner.
22+
error OnlySelf(); // Used when a function is called outside of the contract itself.
23+
error ErrorCase(); // Used when simulating a revert during message processing.
24+
error MessageNotFailed(bytes32 messageId);
25+
26+
27+
}
Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
// SPDX-License-Identifier: MIT
2+
pragma solidity ^0.8.20;
3+
import "./wrapper/CCIPAllowlistedChain.sol";
4+
import "./wrapper/CCIPReceiverDefensive.sol";
5+
import "./internal/CCIPRouterManage.sol";
6+
abstract contract CCIPBaseReceiver is CCIPAllowlistedChain, CCIPReceiverDefensive, CCIPRouterManage {
7+
using EnumerableMap for EnumerableMap.Bytes32ToUintMap;
8+
// Event emitted when a message is received from another chain.
9+
/*event MessageReceived(
10+
bytes32 indexed messageId, // The unique ID of the CCIP message.
11+
uint64 indexed sourceChainSelector, // The chain selector of the source chain.
12+
address sender, // The address of the sender from the source chain.
13+
string text // The text that was received.
14+
);*/
15+
// Event emitted when a message is received from another chain.
16+
event MessageReceived(
17+
bytes32 indexed messageId, // The unique ID of the CCIP message.
18+
uint64 indexed sourceChainSelector, // The chain selector of the source chain.
19+
address sender, // The address of the sender from the source chain.
20+
string text, // The text that was received.
21+
address token, // The token address that was transferred.
22+
uint256 tokenAmount // The token amount that was transferred.
23+
);
24+
25+
/// @notice The entrypoint for the CCIP router to call. This function should
26+
/// never revert, all errors should be handled internally in this contract.
27+
/// @param any2EvmMessage The message to process.
28+
/// @dev Extremely important to ensure only router calls this.
29+
function ccipReceive(
30+
Client.Any2EVMMessage calldata any2EvmMessage
31+
)
32+
external
33+
override
34+
onlyRouter
35+
onlyAllowlisted(
36+
any2EvmMessage.sourceChainSelector,
37+
abi.decode(any2EvmMessage.sender, (address))
38+
) // Make sure the source chain and sender are allowlisted
39+
{
40+
/* solhint-disable no-empty-blocks */
41+
try this.processMessage(any2EvmMessage) {
42+
// Intentionally empty in this example; no action needed if processMessage succeeds
43+
} catch (bytes memory err) {
44+
// Could set different error codes based on the caught error. Each could be
45+
// handled differently.
46+
s_failedMessages.set(
47+
any2EvmMessage.messageId,
48+
uint256(ErrorCode.BASIC)
49+
);
50+
s_messageContents[any2EvmMessage.messageId] = any2EvmMessage;
51+
// Don't revert so CCIP doesn't revert. Emit event instead.
52+
// The message can be retried later without having to do manual execution of CCIP.
53+
emit MessageFailed(any2EvmMessage.messageId, err);
54+
return;
55+
}
56+
}
57+
58+
/// @notice Serves as the entry point for this contract to process incoming messages.
59+
/// @param any2EvmMessage Received CCIP message.
60+
/// @dev Transfers specified token amounts to the owner of this contract. This function
61+
/// must be external because of the try/catch for error handling.
62+
/// It uses the `onlySelf`: can only be called from the contract.
63+
function processMessage(
64+
Client.Any2EVMMessage calldata any2EvmMessage
65+
)
66+
external
67+
onlySelf
68+
onlyAllowlisted(
69+
any2EvmMessage.sourceChainSelector,
70+
abi.decode(any2EvmMessage.sender, (address))
71+
) // Make sure the source chain and sender are allowlisted
72+
{
73+
// Simulate a revert for testing purposes
74+
if (s_simRevert) {
75+
revert CCIPErrors.ErrorCase();
76+
}
77+
_ccipReceive(any2EvmMessage); // process the message - may revert as well
78+
}
79+
80+
/// handle a received message
81+
/*function _ccipReceive(
82+
Client.Any2EVMMessage memory any2EvmMessage
83+
)
84+
internal
85+
override
86+
onlyAllowlisted(
87+
any2EvmMessage.sourceChainSelector,
88+
abi.decode(any2EvmMessage.sender, (address))
89+
) // Make sure source chain and sender are allowlisted
90+
{
91+
// fetch the messageId
92+
s_lastReceivedMessageId = any2EvmMessage.messageId;
93+
// abi-decoding of the sent text
94+
s_lastReceivedText = abi.decode(any2EvmMessage.data, (string));
95+
96+
emit MessageReceived(
97+
any2EvmMessage.messageId,
98+
any2EvmMessage.sourceChainSelector, // fetch the source chain identifier (aka selector)
99+
abi.decode(any2EvmMessage.sender, (address)), // abi-decoding of the sender address,
100+
abi.decode(any2EvmMessage.data, (string))
101+
);
102+
}*/
103+
104+
function _ccipReceive(
105+
Client.Any2EVMMessage memory any2EvmMessage
106+
) internal override {
107+
s_lastReceivedMessageId = any2EvmMessage.messageId; // fetch the messageId
108+
s_lastReceivedText = abi.decode(any2EvmMessage.data, (string)); // abi-decoding of the sent text
109+
// Expect one token to be transferred at once, but you can transfer several tokens.
110+
s_lastReceivedTokenAddress = any2EvmMessage.destTokenAmounts[0].token;
111+
s_lastReceivedTokenAmount = any2EvmMessage.destTokenAmounts[0].amount;
112+
emit MessageReceived(
113+
any2EvmMessage.messageId,
114+
any2EvmMessage.sourceChainSelector, // fetch the source chain identifier (aka selector)
115+
abi.decode(any2EvmMessage.sender, (address)), // abi-decoding of the sender address,
116+
abi.decode(any2EvmMessage.data, (string)),
117+
any2EvmMessage.destTokenAmounts[0].token,
118+
any2EvmMessage.destTokenAmounts[0].amount
119+
);
120+
}
121+
122+
function supportsInterface(bytes4 interfaceId) public virtual pure override( AuthorizationModule, CCIPReceiverDefensive)
123+
returns (bool){
124+
return ( CCIPReceiverDefensive.supportsInterface(interfaceId) || AuthorizationModule.supportsInterface(interfaceId));
125+
126+
}
127+
}

0 commit comments

Comments
 (0)