Skip to content

Commit cf3909b

Browse files
test env up
1 parent c2843cd commit cf3909b

File tree

11 files changed

+497
-54
lines changed

11 files changed

+497
-54
lines changed

.gitmodules

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,6 @@
77
[submodule "lib/ccip"]
88
path = lib/ccip
99
url = https://github.com/smartcontractkit/ccip
10+
[submodule "lib/chainlink-local"]
11+
path = lib/chainlink-local
12+
url = https://github.com/smartcontractkit/chainlink-local

foundry.toml

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,16 @@ libs = ["lib"]
55

66
remappings = [
77
"@openzeppelin/=lib/openzeppelin-contracts/",
8-
'@ccip/=lib/ccip/'
8+
'@ccip/=lib/ccip/',
9+
'@chainlink-local/=lib/chainlink-local/'
910
]
1011
[fuzz]
1112
run=250
13+
14+
rpc_endpoints = { sepolia = "YOUR_SEPOLIA_RPC_URL_HERE", arb-sepolia = "YOUR_ARB_SEPOLIA_RPC_URL_HERE" }
15+
# ... remappings​
16+
# Ensure you replace YOUR_SEPOLIA_RPC_URL_HERE and YOUR_ARB_SEPOLIA_RPC_URL_HERE
17+
# with your actual RPC provider URLs.
1218
# See more config options https://github.com/foundry-rs/foundry/blob/master/crates/config/README.md#all-options
1319

1420

lib/chainlink-local

Submodule chainlink-local added at e0954c8

script/ConfigurePool.s.sol

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
// SPDX-License-Identifier: MIT
2+
pragma solidity ^0.8.24;
3+
4+
import {Script} from "forge-std/Script.sol";
5+
import {TokenPool} from "@ccip/contracts/src/v0.8/ccip/pools/TokenPool.sol";
6+
import {RateLimiter} from "@ccip/contracts/src/v0.8/ccip/libraries/RateLimiter.sol";
7+
8+
9+
contract ConfigurePoolScript is Script {
10+
function run(
11+
address localPool,
12+
uint64 remoteChainSelector,
13+
address remotePool,
14+
address remoteToken,
15+
bool outboundRateLimiterIsEnabled,
16+
uint128 outboundRateLimiterCapacity,
17+
uint128 outboundRateLimiterRate,
18+
bool inboundRateLimiterIsEnabled,
19+
uint128 inboundRateLimiterCapacity,
20+
uint128 inboundRateLimiterRate
21+
) public {
22+
vm.startBroadcast();
23+
24+
// Prepare remotePoolAddresses (needs to be bytes[])
25+
bytes[] memory remotePoolAddresses_ = new bytes[](1);
26+
remotePoolAddresses_[0] = abi.encode(remotePool);​
27+
// Prepare remoteTokenAddress (needs to be bytes)
28+
bytes memory remoteTokenAddress_ = abi.encode(remoteToken);​
29+
TokenPool.ChainUpdate[] memory chainsToAdd = new TokenPool.ChainUpdate[](1);​
30+
chainsToAdd[0] = TokenPool.ChainUpdate({
31+
chainSelector: remoteChainSelector,
32+
remotePoolAddresses: remotePoolAddresses_,
33+
remoteTokenAddress: remoteTokenAddress_,
34+
outboundRateLimiterConfig: RateLimiter.Config({
35+
isEnabled: outboundRateLimiterIsEnabled,
36+
capacity: outboundRateLimiterCapacity,
37+
rate: outboundRateLimiterRate
38+
}),
39+
inboundRateLimiterConfig: RateLimiter.Config({
40+
isEnabled: inboundRateLimiterIsEnabled,
41+
capacity: inboundRateLimiterCapacity,
42+
rate: inboundRateLimiterRate
43+
})
44+
});
45+
46+
// Cast localPool address to TokenPool contract type
47+
TokenPool(localPool).applyChainUpdates(
48+
new uint64[](0), // Chains to remove (empty array)
49+
chainsToAdd // Chains to add/update
50+
);
51+
vm.stopBroadcast();
52+
}
53+
}

script/Deployer.s.sol

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
// SPDX-License-Identifier: MIT
2+
pragma solidity ^0.8.24;
3+
4+
5+
import {Script} from "forge-std/Script.sol";
6+
import {RebaseToken} from "../src/RebaseToken.sol";
7+
import {RebaseTokenPool} from "../src/RebaseTokenPool.sol";
8+
import {Vault} from "../src/Vault.sol";
9+
// import {IRebaseToken} from "../src/interfaces/IRebaseToken.sol";
10+
import {CCIPLocalSimulatorFork, Register} from "@chainlink-local/src/ccip/CCIPLocalSimulatorFork.sol";
11+
import {IERC20} from "@ccip/contracts/src/v0.8/vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/IERC20.sol";
12+
import {RegistryModuleOwnerCustom} from "@ccip/contracts/src/v0.8/ccip/RegistryModuleOwnerCustom.sol";
13+
import {TokenAdminRegistry} from "@ccip/contracts/src/v0.8/ccip/TokenAdminRegistry.sol";
14+
15+
16+
17+
contract TokenAndPoolDeployer is Script {
18+
19+
// Implementation for RebaseToken and RebaseTokenPool deployment will be added here.
20+
function run() public returns (RebaseToken token, RebaseTokenPool pool) {
21+
CCIPLocalSimulatorFork ccipLocalSimulatorFork = new CCIPLocalSimulatorFork();
22+
Register.NetworkDetails memory networkDetails = ccipLocalSimulatorFork.getNetworkDetails(block.chainid);
23+
// Deployment and configuration logic
24+
vm.startBroadcast();
25+
token = new RebaseToken();
26+
pool = new RebaseTokenPool(
27+
IERC20(address(token)), // The deployed token address
28+
new address[](0), // Empty allowlist
29+
networkDetails.rmnProxyAddress, // RMN Proxy address from simulator
30+
networkDetails.routerAddress // Router address from simulator
31+
);
32+
33+
token.grantMintAndBurnRole(address(pool));
34+
//------------- CCIP CONFIGURATIONS -----------------------
35+
//register admin
36+
RegistryModuleOwnerCustom(networkDetails.registryModuleOwnerCustomAddress)
37+
.registerAdminViaOwner(address(token));
38+
//accept admin role
39+
TokenAdminRegistry(networkDetails.tokenAdminRegistryAddress)
40+
.acceptAdminRole(address(token));
41+
//set pool
42+
TokenAdminRegistry(networkDetails.tokenAdminRegistryAddress)
43+
.setPool(address(token), address(pool));
44+
vm.stopBroadcast();
45+
46+
}
47+
}
48+
49+
50+
contract VaultDeployer is Script {
51+
// Implementation for Vault deployment will be detailed below.
52+
function run(address _rebaseToken) public returns (Vault vault) {
53+
vm.startBroadcast();
54+
vault = new Vault(IRebaseToken(_rebaseToken)); // 'vault' is now assigned to the return variable
55+
IRebaseToken(_rebaseToken).grantMintAndBurnRole(address(vault));
56+
vm.stopBroadcast();
57+
// Foundry implicitly returns the 'vault' instance here
58+
}
59+
}

src/RebaseToken.sol

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,14 @@ contract RebaseToken is ERC20, Ownable, AccessControl {
137137
return super.transfer(_spender, _amount);
138138
}
139139

140+
/**
141+
*
142+
* @param _account account of contract / user to be given acess to mint and burm
143+
*/
144+
function grantMintAndBurnRole(address _account) external onlyOwner {
145+
_grantRole(MINT_AND_BURN_ROLE, _account); // MINT_AND_BURN_ROLE is a bytes32 identifier
146+
}
147+
140148
/**
141149
* @notice Returns the current balance of an account, including accrued interest.
142150
* @param _user The address of the account.
@@ -186,8 +194,6 @@ contract RebaseToken is ERC20, Ownable, AccessControl {
186194
}
187195

188196
//------------- getters, views and pure functions ---------------------------------------
189-
190-
191197

192198
/**
193199
* @notice Gets the principle balance of a user (tokens actually minted to them), excluding any accrued interest.
@@ -206,8 +212,8 @@ contract RebaseToken is ERC20, Ownable, AccessControl {
206212
return s_interestRate;
207213
}
208214

209-
//get user's interets rate
210-
function getUserInterestRate(address _user) external returns (uint256){
215+
//get user's interets rate
216+
function getUserInterestRate(address _user) external returns (uint256) {
211217
return s_userInterestRate[_user];
212218
}
213219
}

src/RebaseTokenPool.sol

Lines changed: 38 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,61 +1,58 @@
11
//SPDX-License-Identifier:MIT
2-
pragma solidity^0.8.24;
2+
pragma solidity ^0.8.24;
33

44
import {TokenPool} from "@ccip/contracts/src/v0.8/ccip/pools/TokenPool.sol";
55
import {IERC20} from "@ccip/contracts/src/v0.8/vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/IERC20.sol";
66
import {IRebaseToken} from "./interfaces/IRebaseToken.sol"; // Adjust path if your interface is elsewhere
77
import {Pool} from "@ccip/contracts/src/v0.8/ccip/libraries/Pool.sol"; // For CCIP structs
88

9-
contract RebaseTokenPool is TokenPool{
10-
11-
/*** The TokenPool base constructor requires:
12-
* @_token: The address of the rebase token this pool will manage.
13-
* @
14-
* @localTokenDecimals: The decimals of the token. Here, it's hardcoded to 18.
15-
* @
16-
* @_allowlist: An array of addresses permitted to send tokens through this pool.
17-
* @
18-
* @_rnmProxy: The address of the CCIP Risk Management Network (RMN) proxy.
19-
* @
20-
* @_router: The address of the CCIP router contract.
21-
*/
22-
constructor (
23-
IERC20 _token,
24-
address[] memory _allowList,
25-
address i_rmnProxy,
26-
address _router
27-
)TokenPool(_token,_allowList,i_rmnProxy,_router){
28-
//constructor body
29-
}
30-
9+
contract RebaseTokenPool is TokenPool {
10+
/**
11+
* The TokenPool base constructor requires:
12+
* @_token: The address of the rebase token this pool will manage.
13+
* @
14+
* @localTokenDecimals: The decimals of the token. Here, it's hardcoded to 18.
15+
* @
16+
* @_allowlist: An array of addresses permitted to send tokens through this pool.
17+
* @
18+
* @_rnmProxy: The address of the CCIP Risk Management Network (RMN) proxy.
19+
* @
20+
* @_router: The address of the CCIP router contract.
21+
*/
22+
constructor(IERC20 _token, address[] memory _allowList, address i_rmnProxy, address _router)
23+
TokenPool(_token, _allowList, i_rmnProxy, _router)
24+
{
25+
//constructor body
26+
}
3127

32-
// lockorburn function to process burning upon transfering
33-
function lockOrBurn(Pool.LockOrBurnInV1 calldata lockOrBurnIn) external returns (Pool.LockOrBurnOutV1 memory lockOrBurnOut) {
28+
// lockorburn function to process burning upon transfering
29+
function lockOrBurn(Pool.LockOrBurnInV1 calldata lockOrBurnIn)
30+
external
31+
override
32+
returns (Pool.LockOrBurnOutV1 memory lockOrBurnOut)
33+
{
3434
_validateLockOrBurn(lockOrBurnIn);
35-
// Decode the original sender's address
36-
address originalSender = abi.decode(lockOrBurnIn.originalSender, (address));
37-
38-
// Fetch the user's current interest rate from the rebase token
39-
uint256 userInterestRate = IRebaseToken(address(i_token)).getUserInterestRate(originalSender);
40-
// Burn the specified amount of tokens from this pool contract
41-
// CCIP transfers tokens to the pool before lockOrBurn is called
35+
// Burn the tokens on the source chain. This returns their userAccumulatedInterest before the tokens were burned (in case all tokens were burned, we don't want to send 0 cross-chain)
36+
uint256 userInterestRate = IRebaseToken(address(i_token)).getUserInterestRate(lockOrBurnIn.originalSender);
4237
IRebaseToken(address(i_token)).burn(address(this), lockOrBurnIn.amount);
43-
// Prepare the output data for CCIP
38+
// encode a function call to pass the caller's info to the destination pool and update it
4439
lockOrBurnOut = Pool.LockOrBurnOutV1({
4540
destTokenAddress: getRemoteToken(lockOrBurnIn.remoteChainSelector),
46-
destPoolData: abi.encode(userInterestRate) // Encode the interest rate to send cross-chain
41+
destPoolData: abi.encode(userInterestRate)
4742
});
48-
// No explicit return statement is needed due to the named return variable
43+
// because of named return variable in the function signature : no explicit return statement is needed
4944
}
5045

5146
// when tokens are beign receive on the chain where this RebaseTokenPool is deployed
52-
function releaseOrMint(
53-
Pool.ReleaseOrMintInV1 calldata releaseOrMintIn
54-
) external override returns (Pool.ReleaseOrMintOutV1 memory /* releaseOrMintOut */) { // Named return optional
47+
function releaseOrMint(Pool.ReleaseOrMintInV1 calldata releaseOrMintIn)
48+
external
49+
override
50+
returns (Pool.ReleaseOrMintOutV1 memory /* releaseOrMintOut */ )
51+
{
52+
// Named return optional
5553
_validateReleaseOrMint(releaseOrMintIn);
5654
// Decode the user interest rate sent from the source pool
5755
uint256 userInterestRate = abi.decode(releaseOrMintIn.sourcePoolData, (uint256));
58-
5956
// The receiver address is directly available
6057
address receiver = releaseOrMintIn.receiver;
6158
// Mint tokens to the receiver, applying the propagated interest rate
@@ -64,9 +61,6 @@ contract RebaseTokenPool is TokenPool{
6461
releaseOrMintIn.amount,
6562
userInterestRate // Pass the interest rate to the rebase token's mint function
6663
);
67-
return Pool.ReleaseOrMintOutV1({
68-
destinationAmount: releaseOrMintIn.amount
69-
});
64+
return Pool.ReleaseOrMintOutV1({destinationAmount: releaseOrMintIn.amount});
7065
}
71-
72-
}
66+
}

src/Vault.sol

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,10 @@ contract Vault {
2929
if (amountToDeposite == 0) {
3030
revert Vault_NotEthSent();
3131
}
32+
// get interest rete
33+
uint256 interestRate = i_rebaseToken.getUserInterestRate(msg.sender);
3234
// give mint
33-
i_rebaseToken.mint(msg.sender, amountToDeposite);
35+
i_rebaseToken.mint(msg.sender, amountToDeposite, interestRate);
3436

3537
emit Vault_EthDeposited(msg.sender, amountToDeposite);
3638
}

src/interfaces/IRebaseToken.sol

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ interface IRebaseToken {
88
* @param _to The address to mint tokens to.
99
* @param _amount The amount of tokens to mint.
1010
*/
11-
function mint(address _to, uint256 _amount) external;
11+
function mint(address _to, uint256 _amount, uint256 _interestRate) external;
1212
/**
1313
* @notice Burns tokens from a specified address.
1414
* @param _from The address to burn tokens from.
@@ -17,4 +17,11 @@ interface IRebaseToken {
1717
function burn(address _from, uint256 _amount) external;
1818
// Note: We only include functions that the Vault contract will call.
1919
// Other functions from the actual RebaseToken.sol are not needed here.
20+
21+
function grantMintAndBurnRole(address _user) external;
22+
/**
23+
* @param _account the user whose locked interest rate is to be retrieved
24+
* @return uint256 the locked interest rate
25+
*/
26+
function getUserInterestRate(address _account) external view returns (uint256);
2027
}

0 commit comments

Comments
 (0)