Skip to content

Commit

Permalink
initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
lucasfernandes committed Sep 10, 2024
1 parent 9d09781 commit 5dfd26e
Show file tree
Hide file tree
Showing 17 changed files with 604 additions and 59 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,4 @@ docs/

# Dotenv file
.env
node_modules
6 changes: 6 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
[submodule "lib/forge-std"]
path = lib/forge-std
url = https://github.com/foundry-rs/forge-std
[submodule "lib/ccip"]
path = lib/ccip
url = https://github.com/smartcontractkit/ccip
[submodule "lib/chainlink-local"]
path = lib/chainlink-local
url = https://github.com/smartcontractkit/chainlink-local
16 changes: 14 additions & 2 deletions foundry.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,18 @@
[profile.default]
viaIrl = true

src = "src"
out = "out"
libs = ["lib"]

# See more config options https://github.com/foundry-rs/foundry/blob/master/crates/config/README.md#all-options
remappings = ['@chainlink/local=lib/chainlink-local/src/ccip/']
solc = '0.8.27'
[rpc_endpoints]
ethereumSepolia = "${ETHEREUM_SEPOLIA_RPC_URL}"
optimismGoerli = "${OPTIMISM_GOERLI_RPC_URL}"
avalancheFuji = "${AVALANCHE_FUJI_RPC_URL}"
arbitrumSepolia = "${ARBITRUM_SEPOLIA_RPC_URL}"
polygonMumbai = "${POLYGON_MUMBAI_RPC_URL}"
bnbChainTestnet = "${BNB_CHAIN_TESTNET_RPC_URL}"
baseSepolia = "${BASE_SEPOLIA_RPC_URL}"
metisSepolia = "${METIS_SEPOLIA_RPC_URL}"
zksyncSepolia = "${ZKSYNC_SEPOLIA_RPC_URL}"
126 changes: 126 additions & 0 deletions lcov.info
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
TN:
SF:src/Answer.sol
FN:21,Answer.
FNDA:3,Answer.
DA:22,3
DA:23,3
DA:24,3
FN:27,Answer._ccipReceive
FNDA:3,Answer._ccipReceive
DA:28,3
DA:29,3
DA:31,3
DA:33,3
DA:41,3
DA:42,3
DA:44,3
FN:47,Answer.getLastReceivedMessageDetails
FNDA:3,Answer.getLastReceivedMessageDetails
DA:52,3
FN:55,Answer.previewFees
FNDA:3,Answer.previewFees
DA:60,6
DA:61,6
FN:64,Answer.answerTier
FNDA:0,Answer.answerTier
DA:68,3
DA:70,3
DA:72,3
BRDA:72,0,0,-
BRDA:72,0,1,3
DA:77,3
DA:78,3
DA:79,3
DA:83,3
FN:86,Answer.mountMessage
FNDA:9,Answer.mountMessage
DA:91,9
DA:99,9
FNF:6
FNH:5
LF:22
LH:22
BRF:2
BRH:1
end_of_record
TN:
SF:src/Ask.sol
FN:17,Ask.
FNDA:3,Ask.
DA:18,3
DA:19,3
FN:22,Ask.previewFees
FNDA:3,Ask.previewFees
DA:27,6
DA:28,6
FN:31,Ask.askTier
FNDA:3,Ask.askTier
DA:35,3
DA:36,3
DA:38,3
BRDA:38,0,0,-
BRDA:38,0,1,3
DA:43,3
DA:44,3
DA:45,3
DA:49,3
FN:52,Ask._ccipReceive
FNDA:3,Ask._ccipReceive
DA:53,3
DA:55,3
FN:58,Ask.mountMessage
FNDA:9,Ask.mountMessage
DA:59,9
DA:67,9
FNF:5
FNH:5
LF:15
LH:15
BRF:2
BRH:1
end_of_record
TN:
SF:src/Points.sol
FN:7,Points.grantPoints
FNDA:9,Points.grantPoints
DA:8,9
FNF:1
FNH:1
LF:1
LH:1
BRF:0
BRH:0
end_of_record
TN:
SF:src/Tiers.sol
FN:13,Tiers.
FNDA:3,Tiers.
DA:14,3
FN:23,Tiers.addTier
FNDA:15,Tiers.addTier
DA:24,15
DA:25,15
DA:26,15
FN:34,Tiers.getTier
FNDA:3,Tiers.getTier
DA:36,3
DA:39,3
DA:41,10
DA:42,3
BRDA:42,0,0,3
DA:43,3
DA:48,0
FN:56,Tiers.getTierByName
FNDA:0,Tiers.getTierByName
DA:57,0
DA:59,0
DA:60,0
DA:61,0
DA:65,0
FNF:4
FNH:3
LF:15
LH:9
BRF:1
BRH:1
end_of_record
1 change: 1 addition & 0 deletions lib/ccip
Submodule ccip added at 065ef8
1 change: 1 addition & 0 deletions lib/chainlink-local
Submodule chainlink-local added at ba1f46
19 changes: 0 additions & 19 deletions script/Counter.s.sol

This file was deleted.

101 changes: 101 additions & 0 deletions src/Answer.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.27;

import {console} from "forge-std/Test.sol";
import {Client} from "@chainlink/contracts-ccip/src/v0.8/ccip/libraries/Client.sol";
import {CCIPReceiver} from "@chainlink/contracts-ccip/src/v0.8/ccip/applications/CCIPReceiver.sol";
import {IRouterClient} from "@chainlink/contracts-ccip/src/v0.8/ccip/interfaces/IRouterClient.sol";
import {IERC20} from
"@chainlink/contracts-ccip/src/v0.8/vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/IERC20.sol";
import {ICrossChainMessages} from "./interfaces/ICrossChainMessages.sol";
import {ITiers} from "./interfaces/ITiers.sol";

contract Answer is CCIPReceiver {
bytes32 private lastReceivedMessageId;
address private lastReceivedWallet;
string private lastAnswer;
ITiers private samuraiTiers;
IRouterClient private router;
IERC20 private linkToken;

constructor(address _router, address _samuraiTiers, address _link) CCIPReceiver(_router) {
router = IRouterClient(_router);
samuraiTiers = ITiers(_samuraiTiers);
linkToken = IERC20(_link);
}

function _ccipReceive(Client.Any2EVMMessage memory any2EvmMessage) internal override {
lastReceivedMessageId = any2EvmMessage.messageId;
lastReceivedWallet = abi.decode(any2EvmMessage.data, (address));

address receiver = abi.decode(any2EvmMessage.sender, (address));

emit ICrossChainMessages.MessageReceived(
any2EvmMessage.messageId,
any2EvmMessage.sourceChainSelector,
abi.decode(any2EvmMessage.sender, (address)),
abi.decode(any2EvmMessage.data, (address)),
""
);

ITiers.Tier memory tier = samuraiTiers.getTier(lastReceivedWallet);
lastAnswer = tier.name;

answerTier(any2EvmMessage.sourceChainSelector, receiver, lastReceivedWallet, tier.name);
}

function getLastReceivedMessageDetails()
external
view
returns (bytes32 messageId, address wallet, string memory answer)
{
return (lastReceivedMessageId, lastReceivedWallet, lastAnswer);
}

function previewFees(uint64 destinationChainSelector, address receiver, address wallet, string memory tierName)
public
view
returns (uint256)
{
Client.EVM2AnyMessage memory evm2AnyMessage = mountMessage(receiver, wallet, tierName);
return router.getFee(destinationChainSelector, evm2AnyMessage);
}

function answerTier(uint64 destinationChainSelector, address receiver, address wallet, string memory tierName)
public
returns (bytes32 messageId)
{
Client.EVM2AnyMessage memory evm2AnyMessage = mountMessage(receiver, wallet, tierName);

uint256 fees = previewFees(destinationChainSelector, receiver, wallet, tierName);

require(
fees <= linkToken.balanceOf(address(this)),
ICrossChainMessages.NotEnoughBalance(linkToken.balanceOf(address(this)), fees)
);

linkToken.approve(address(router), fees);
messageId = router.ccipSend(destinationChainSelector, evm2AnyMessage);
emit ICrossChainMessages.MessageSent(
messageId, destinationChainSelector, receiver, wallet, tierName, address(linkToken), fees
);

return messageId;
}

function mountMessage(address receiver, address wallet, string memory tierName)
private
view
returns (Client.EVM2AnyMessage memory)
{
Client.EVM2AnyMessage memory evm2AnyMessage = Client.EVM2AnyMessage({
receiver: abi.encode(receiver),
data: abi.encode(wallet, tierName),
tokenAmounts: new Client.EVMTokenAmount[](0),
extraArgs: Client._argsToBytes(Client.EVMExtraArgsV1({gasLimit: 500_000})),
feeToken: address(linkToken)
});

return evm2AnyMessage;
}
}
69 changes: 69 additions & 0 deletions src/Ask.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.27;

import {CCIPReceiver} from "@chainlink/contracts-ccip/src/v0.8/ccip/applications/CCIPReceiver.sol";
import {IRouterClient} from "@chainlink/contracts-ccip/src/v0.8/ccip/interfaces/IRouterClient.sol";
import {Client} from "@chainlink/contracts-ccip/src/v0.8/ccip/libraries/Client.sol";
import {IERC20} from
"@chainlink/contracts-ccip/src/v0.8/vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/IERC20.sol";
import {ICrossChainMessages} from "./interfaces/ICrossChainMessages.sol";
import {console} from "forge-std/Test.sol";

contract Ask is CCIPReceiver {
IRouterClient private router;
IERC20 private linkToken;
mapping(address wallet => string name) public tiers;

constructor(address _router, address _link) CCIPReceiver(_router) {
router = IRouterClient(_router);
linkToken = IERC20(_link);
}

function previewFees(uint64 destinationChainSelector, address receiver, address wallet)
public
view
returns (uint256)
{
Client.EVM2AnyMessage memory evm2AnyMessage = mountMessage(receiver, wallet);
return router.getFee(destinationChainSelector, evm2AnyMessage);
}

function askTier(uint64 destinationChainSelector, address receiver, address wallet)
external
returns (bytes32 messageId)
{
Client.EVM2AnyMessage memory evm2AnyMessage = mountMessage(receiver, wallet);
uint256 fees = previewFees(destinationChainSelector, receiver, wallet);

require(
fees <= linkToken.balanceOf(address(this)),
ICrossChainMessages.NotEnoughBalance(linkToken.balanceOf(address(this)), fees)
);

linkToken.approve(address(router), fees);
messageId = router.ccipSend(destinationChainSelector, evm2AnyMessage);
emit ICrossChainMessages.MessageSent(
messageId, destinationChainSelector, receiver, wallet, "", address(linkToken), fees
);

return messageId;
}

function _ccipReceive(Client.Any2EVMMessage memory any2EvmMessage) internal override {
(address wallet, string memory tierName) = abi.decode(any2EvmMessage.data, (address, string));

tiers[wallet] = tierName;
}

function mountMessage(address receiver, address wallet) private view returns (Client.EVM2AnyMessage memory) {
Client.EVM2AnyMessage memory evm2AnyMessage = Client.EVM2AnyMessage({
receiver: abi.encode(receiver),
data: abi.encode(wallet),
tokenAmounts: new Client.EVMTokenAmount[](0),
extraArgs: Client._argsToBytes(Client.EVMExtraArgsV1({gasLimit: 500_000})),
feeToken: address(linkToken)
});

return evm2AnyMessage;
}
}
14 changes: 0 additions & 14 deletions src/Counter.sol

This file was deleted.

10 changes: 10 additions & 0 deletions src/Points.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.27;

contract Points {
mapping(address wallet => uint256 walletPoints) public walletsPoints;

function grantPoints(address wallet, uint256 points) external {
walletsPoints[wallet] = points;
}
}
Loading

0 comments on commit 5dfd26e

Please sign in to comment.