Skip to content

Commit 64b3128

Browse files
notbduRnkSngh
authored andcommitted
add polymer cctp facet + deploy scripts
1 parent 98bde03 commit 64b3128

File tree

10 files changed

+554
-0
lines changed

10 files changed

+554
-0
lines changed

foundry.lock

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
{
2+
"lib/Permit2": {
3+
"rev": "cc56ad0f3439c502c246fc5cfcc3db92bb8b7219"
4+
},
5+
"lib/create3-factory": {
6+
"rev": "0c1f388914a9c5e1c1731af31e8340952b0cbe9e"
7+
},
8+
"lib/ds-test": {
9+
"rev": "e282159d5170298eb2455a6c05280ab5a73a4ef0"
10+
},
11+
"lib/forge-std": {
12+
"rev": "7f7cb06aa55fc75d2280d7d54713dc4368d71fd3"
13+
},
14+
"lib/openzeppelin-contracts": {
15+
"rev": "e50c24f5839db17f46991478384bfda14acfb830"
16+
},
17+
"lib/safe-tx-cli": {
18+
"rev": "c8edc3242cc8720c08ce02be0075fb9189d3e560"
19+
},
20+
"lib/sgn-v2-contracts": {
21+
"rev": "1782ba66c6e510337e98f82c857f83d49aa4b13d"
22+
},
23+
"lib/solady": {
24+
"rev": "678c9163550810b08f0ffb09624c9f7532392303"
25+
},
26+
"lib/solmate": {
27+
"rev": "2001af43aedb46fdc2335d2a7714fb2dae7cfcd1"
28+
}
29+
}
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
#!/bin/bash
2+
3+
# Exit on error
4+
set -e
5+
6+
# Color codes for output
7+
GREEN='\033[0;32m'
8+
BLUE='\033[0;34m'
9+
RED='\033[0;31m'
10+
YELLOW='\033[1;33m'
11+
NC='\033[0m' # No Color
12+
13+
# Function to display usage
14+
usage() {
15+
echo "Usage: $0 <RPC_URL> <PRIVATE_KEY> <DESTINATION_DOMAIN> <ADDRESSES_FILE>"
16+
echo ""
17+
echo "Required arguments:"
18+
echo " RPC_URL RPC endpoint URL"
19+
echo " PRIVATE_KEY Private key for deployment"
20+
echo " DESTINATION_DOMAIN Destination domain for CCTP bridge"
21+
echo " ADDRESSES_FILE Path to addresses json"
22+
echo ""
23+
echo "Example:"
24+
echo " $0 https://arb-sepolia.g.alchemy.com/v2/KEY 0xYOURKEY 3 ./testnet-addresses.json"
25+
exit 1
26+
}
27+
28+
# Check if we have the required number of arguments
29+
if [ $# -lt 4 ]; then
30+
echo -e "${RED}Error: Missing required arguments${NC}\n"
31+
usage
32+
fi
33+
34+
# Parse positional arguments
35+
RPC_URL="$1"
36+
PRIVATE_KEY="$2"
37+
DESTINATION_DOMAIN="$3"
38+
ADDRESSES_FILE="$4"
39+
40+
# Get chain ID from RPC
41+
echo -e "${BLUE}Fetching chain ID from RPC...${NC}"
42+
CHAIN_ID=$(cast chain-id -r "$RPC_URL")
43+
if [ -z "$CHAIN_ID" ]; then
44+
echo -e "${RED}Error: Could not fetch chain ID from RPC${NC}"
45+
exit 1
46+
fi
47+
echo -e "${GREEN}Chain ID: $CHAIN_ID${NC}"
48+
49+
# Read DIAMOND_ADDRESS and USDC from addresses.json
50+
DIAMOND_ADDRESS=$(jq -r --arg chainId "$CHAIN_ID" '.[$chainId].diamondProxy // empty' "$ADDRESSES_FILE")
51+
if [ -z "$DIAMOND_ADDRESS" ]; then
52+
echo -e "${RED}Error: DIAMOND_ADDRESS not found in $ADDRESSES_FILE for chain $CHAIN_ID${NC}"
53+
echo "Please deploy the diamond first using DeployPolymerContracts.sh"
54+
exit 1
55+
fi
56+
echo -e "${BLUE}Using DIAMOND_ADDRESS from $ADDRESSES_FILE: $DIAMOND_ADDRESS${NC}"
57+
58+
if [ -z "$USDC" ]; then
59+
USDC=$(jq -r --arg chainId "$CHAIN_ID" '.[$chainId].usdc // empty' "$ADDRESSES_FILE")
60+
if [ -z "$USDC" ]; then
61+
echo -e "${RED}Error: USDC not found in $ADDRESSES_FILE for chain $CHAIN_ID and not set in environment${NC}"
62+
echo "Please either:"
63+
echo " 1. Set USDC environment variable, or"
64+
echo " 2. Add it to $ADDRESSES_FILE under \"$CHAIN_ID\": { \"usdc\": \"0x...\" }"
65+
exit 1
66+
fi
67+
echo -e "${BLUE}Using USDC from $ADDRESSES_FILE: $USDC${NC}"
68+
fi
69+
70+
# Export all variables for forge scripts
71+
export RPC_URL
72+
export CHAIN_ID
73+
export PRIVATE_KEY
74+
export DESTINATION_DOMAIN
75+
export DIAMOND_ADDRESS
76+
export USDC
77+
78+
echo -e "${BLUE}Calling PolymerCCTPFacet on chain $CHAIN_ID...${NC}"
79+
80+
# Run the call script
81+
forge script ./script/demoScripts/PolymerCCTP.s.sol \
82+
--rpc-url "$RPC_URL" \
83+
--broadcast \
84+
--verify
85+
86+
echo -e "${GREEN}PolymerCCTP call complete!${NC}"
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
// SPDX-License-Identifier: UNLICENSED
2+
pragma solidity ^0.8.17;
3+
4+
import {Script, console2} from "forge-std/Script.sol";
5+
import {LiFiDiamond} from "lifi/LiFiDiamond.sol";
6+
import {PolymerCCTPFacet} from "lifi/Facets/PolymerCCTPFacet.sol";
7+
import {ILiFi} from "lifi/Interfaces/ILiFi.sol";
8+
import {LibSwap} from "lifi/Libraries/LibSwap.sol";
9+
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
10+
import {PolymerCCTPData} from "lifi/Interfaces/IPolymerCCTP.sol";
11+
12+
contract CallPolymerCCTPFacet is Script {
13+
function run() external payable {
14+
uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY");
15+
address diamondAddress = vm.envAddress("DIAMOND_ADDRESS");
16+
uint32 destinationDomain = uint32(vm.envUint("DESTINATION_DOMAIN"));
17+
address receiver = vm.addr(deployerPrivateKey);
18+
uint256 amount = uint256(1000);
19+
uint256 polymerTokenFee = uint256(10);
20+
uint32 maxCCTPFee = uint32(vm.envOr("MAX_CCTP_FEE", uint256(100)));
21+
uint32 minFinalityThreshold = uint32(vm.envOr("MIN_FINALITY_THRESHOLD", uint256(0)));
22+
23+
// Cast diamond to PolymerCCTPFacet to call its functions
24+
PolymerCCTPFacet polymerFacet = PolymerCCTPFacet(diamondAddress);
25+
address usdcAddress = vm.envAddress("USDC");
26+
27+
// Get USDC address from the PolymerCCTPFacet
28+
console2.log("USDC address:", usdcAddress);
29+
30+
vm.startBroadcast(deployerPrivateKey);
31+
32+
// Approve USDC spending
33+
IERC20(usdcAddress).approve(diamondAddress, amount + polymerTokenFee);
34+
35+
// Prepare bridge data
36+
ILiFi.BridgeData memory bridgeData = ILiFi.BridgeData({
37+
transactionId: bytes32(uint256(1)), // Simple transaction ID
38+
bridge: "PolymerCCTP",
39+
integrator: "LiFi",
40+
referrer: address(0),
41+
sendingAssetId: usdcAddress,
42+
receiver: receiver,
43+
minAmount: amount,
44+
destinationChainId: uint256(destinationDomain), // Using domain as chain ID for simplicity
45+
hasSourceSwaps: false,
46+
hasDestinationCall: false
47+
});
48+
49+
// Prepare Polymer-specific data
50+
PolymerCCTPData memory polymerData = PolymerCCTPData({
51+
polymerTokenFee: polymerTokenFee,
52+
maxCCTPFee: maxCCTPFee,
53+
minFinalityThreshold: minFinalityThreshold,
54+
nonEvmAddress: bytes32(0)
55+
});
56+
57+
console2.log("Calling startBridgeTokensViaPolymerCCTP...");
58+
console2.log("Amount:", amount);
59+
console2.log("Destination Domain:", destinationDomain);
60+
console2.log("Receiver:", receiver);
61+
62+
// Call the bridge function
63+
polymerFacet.startBridgeTokensViaPolymerCCTP(bridgeData, polymerData);
64+
65+
console2.log("Bridge transaction initiated successfully");
66+
67+
vm.stopBroadcast();
68+
}
69+
}
Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
#!/bin/bash
2+
3+
# Exit on error
4+
set -e
5+
6+
# Color codes for output
7+
GREEN='\033[0;32m'
8+
BLUE='\033[0;34m'
9+
RED='\033[0;31m'
10+
YELLOW='\033[1;33m'
11+
NC='\033[0m' # No Color
12+
13+
# Function to display usage
14+
usage() {
15+
echo "Usage: $0 <RPC_URL> <PRIVATE_KEY> [OPTIONS]"
16+
echo ""
17+
echo "Required arguments:"
18+
echo " RPC_URL RPC endpoint URL"
19+
echo " PRIVATE_KEY Private key for deployment"
20+
echo " ADDRESSES_FILE Path to addresses json"
21+
echo ""
22+
echo "Example:"
23+
echo " $0 https://arb-sepolia.g.alchemy.com/v2/KEY 0xYOURKEY 3"
24+
exit 1
25+
}
26+
27+
# Check if we have the required number of arguments
28+
if [ $# -lt 3 ]; then
29+
echo -e "${RED}Error: Missing required arguments${NC}\n"
30+
usage
31+
fi
32+
33+
# Parse positional arguments
34+
RPC_URL="$1"
35+
PRIVATE_KEY="$2"
36+
ADDRESSES_FILE="$3"
37+
38+
# Get chain ID from RPC
39+
echo -e "${BLUE}Fetching chain ID from RPC...${NC}"
40+
CHAIN_ID=$(cast chain-id -r "$RPC_URL")
41+
if [ -z "$CHAIN_ID" ]; then
42+
echo -e "${RED}Error: Could not fetch chain ID from RPC${NC}"
43+
exit 1
44+
fi
45+
echo -e "${GREEN}Chain ID: $CHAIN_ID${NC}"
46+
47+
# # Use ADDRESSES_PATH env var or default to addresses.json
48+
49+
# Create addresses file if it doesn't exist
50+
if [ ! -f "$ADDRESSES_FILE" ]; then
51+
echo "{}" > "$ADDRESSES_FILE"
52+
echo -e "${BLUE}Created $ADDRESSES_FILE${NC}"
53+
fi
54+
55+
# Read TOKEN_MESSENGER, USDC, and POLYMER_FEE_RECIPIENT from addresses.json if not set in env
56+
if [ -z "$TOKEN_MESSENGER" ]; then
57+
TOKEN_MESSENGER=$(jq -r --arg chainId "$CHAIN_ID" '.[$chainId].tokenMessenger // empty' "$ADDRESSES_FILE")
58+
if [ -z "$TOKEN_MESSENGER" ]; then
59+
echo -e "${RED}Error: TOKEN_MESSENGER not found in $ADDRESSES_FILE for chain $CHAIN_ID and not set in environment${NC}"
60+
echo "Please either:"
61+
echo " 1. Set TOKEN_MESSENGER environment variable, or"
62+
echo " 2. Add it to $ADDRESSES_FILE under \"$CHAIN_ID\": { \"tokenMessenger\": \"0x...\" }"
63+
exit 1
64+
fi
65+
echo -e "${BLUE}Using TOKEN_MESSENGER from $ADDRESSES_FILE: $TOKEN_MESSENGER${NC}"
66+
fi
67+
68+
if [ -z "$USDC" ]; then
69+
USDC=$(jq -r --arg chainId "$CHAIN_ID" '.[$chainId].usdc // empty' "$ADDRESSES_FILE")
70+
if [ -z "$USDC" ]; then
71+
echo -e "${RED}Error: USDC not found in $ADDRESSES_FILE for chain $CHAIN_ID and not set in environment${NC}"
72+
echo "Please either:"
73+
echo " 1. Set USDC environment variable, or"
74+
echo " 2. Add it to $ADDRESSES_FILE under \"$CHAIN_ID\": { \"usdc\": \"0x...\" }"
75+
exit 1
76+
fi
77+
echo -e "${BLUE}Using USDC from $ADDRESSES_FILE: $USDC${NC}"
78+
fi
79+
80+
if [ -z "$POLYMER_FEE_RECIPIENT" ]; then
81+
POLYMER_FEE_RECIPIENT=$(jq -r --arg chainId "$CHAIN_ID" '.[$chainId].polymerFeeRecipient // empty' "$ADDRESSES_FILE")
82+
if [ -z "$POLYMER_FEE_RECIPIENT" ]; then
83+
echo -e "${RED}Error: POLYMER_FEE_RECIPIENT not found in $ADDRESSES_FILE for chain $CHAIN_ID and not set in environment${NC}"
84+
echo "Please either:"
85+
echo " 1. Set POLYMER_FEE_RECIPIENT environment variable, or"
86+
echo " 2. Add it to $ADDRESSES_FILE under \"$CHAIN_ID\": { \"usdc\": \"0x...\" }"
87+
exit 1
88+
fi
89+
echo -e "${BLUE}Using POLYMER_FEE_RECIPIENT from $ADDRESSES_FILE: $POLYMER_FEE_RECIPIENT${NC}"
90+
fi
91+
92+
# Export all variables for forge scripts
93+
export RPC_URL
94+
export CHAIN_ID
95+
export PRIVATE_KEY
96+
export TOKEN_MESSENGER
97+
export USDC
98+
export POLYMER_FEE_RECIPIENT
99+
100+
echo -e "${BLUE}Deploying Diamond with PolymerCCTPFacet to chain $CHAIN_ID...${NC}"
101+
102+
# Create temp files for output
103+
DEPLOY_OUTPUT_FILE=$(mktemp /tmp/forge-deploy-output.XXXXXX)
104+
echo -e "${BLUE}Output will be saved to: $DEPLOY_OUTPUT_FILE${NC}"
105+
106+
# Run deployment script and save output to temp file
107+
forge script ./script/deploy/facets/DeployDiamondWithPolymerCCTPFacet.s.sol \
108+
--rpc-url "$RPC_URL" \
109+
--broadcast \
110+
--verify \
111+
2>&1 | tee "$DEPLOY_OUTPUT_FILE"
112+
113+
DEPLOY_OUTPUT=$(cat "$DEPLOY_OUTPUT_FILE")
114+
115+
# Extract diamond address from output
116+
DIAMOND_ADDRESS=$(echo "$DEPLOY_OUTPUT" | grep "LiFiDiamond deployed at: " | awk '{print $4}')
117+
118+
if [ -z "$DIAMOND_ADDRESS" ]; then
119+
echo -e "${RED}Error: Could not extract diamond address from deployment output${NC}"
120+
exit 1
121+
fi
122+
123+
echo -e "${GREEN}Diamond deployed at: $DIAMOND_ADDRESS${NC}"
124+
125+
# Update addresses.json with the new deployment
126+
jq --arg chainId "$CHAIN_ID" \
127+
--arg address "$DIAMOND_ADDRESS" \
128+
'.[$chainId].diamondProxy = $address' \
129+
"$ADDRESSES_FILE" > "$ADDRESSES_FILE.tmp" && mv "$ADDRESSES_FILE.tmp" "$ADDRESSES_FILE"
130+
131+
echo -e "${GREEN}Updated $ADDRESSES_FILE${NC}"
132+
echo -e "${GREEN}Deployment complete!${NC}"
133+
echo -e "${BLUE}To call the facet, run: ./script/deploy/CallPolymerCCTP.sh <RPC_URL> <PRIVATE_KEY> <DESTINATION_DOMAIN> $ADDRESSES_FILE${NC}"
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
// SPDX-License-Identifier: UNLICENSED
2+
pragma solidity ^0.8.17;
3+
4+
import {Script, console2} from "forge-std/Script.sol";
5+
import {LiFiDiamond} from "lifi/LiFiDiamond.sol";
6+
import {DiamondCutFacet} from "lifi/Facets/DiamondCutFacet.sol";
7+
import {PolymerCCTPFacet} from "lifi/Facets/PolymerCCTPFacet.sol";
8+
import {DeployScriptBase} from "./utils/DeployScriptBase.sol";
9+
import {LibDiamond} from "lifi/Libraries/LibDiamond.sol";
10+
11+
contract DeployDiamondWithPolymerCCTPFacet is Script {
12+
function run() external {
13+
uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY");
14+
15+
// Read PolymerCCTPFacet constructor arguments from environment
16+
address tokenMessenger = vm.envAddress("TOKEN_MESSENGER");
17+
address usdc = vm.envAddress("USDC");
18+
address polymerFeeRecipient = vm.envAddress("POLYMER_FEE_RECIPIENT");
19+
20+
vm.startBroadcast(deployerPrivateKey);
21+
22+
// Deploy DiamondCutFacet
23+
console2.log("Deploying DiamondCutFacet...");
24+
DiamondCutFacet diamondCutFacet = new DiamondCutFacet();
25+
console2.log("DiamondCutFacet deployed at:", address(diamondCutFacet));
26+
27+
// Deploy LiFiDiamond
28+
console2.log("Deploying LiFiDiamond...");
29+
LiFiDiamond diamond = new LiFiDiamond(vm.addr(deployerPrivateKey), address(diamondCutFacet));
30+
console2.log("LiFiDiamond deployed at:", address(diamond));
31+
32+
// Deploy PolymerCCTPFacet
33+
console2.log("Deploying PolymerCCTPFacet...");
34+
PolymerCCTPFacet polymerCCTPFacet = new PolymerCCTPFacet(tokenMessenger, usdc, polymerFeeRecipient);
35+
console2.log("PolymerCCTPFacet deployed at:", address(polymerCCTPFacet));
36+
37+
// Add PolymerCCTPFacet to diamond
38+
console2.log("Adding PolymerCCTPFacet to diamond...");
39+
bytes4[] memory selectors = new bytes4[](1);
40+
selectors[0] = PolymerCCTPFacet.startBridgeTokensViaPolymerCCTP.selector;
41+
42+
LibDiamond.FacetCut[] memory cuts = new LibDiamond.FacetCut[](1);
43+
cuts[0] = LibDiamond.FacetCut({
44+
facetAddress: address(polymerCCTPFacet),
45+
action: LibDiamond.FacetCutAction.Add,
46+
functionSelectors: selectors
47+
});
48+
49+
DiamondCutFacet(address(diamond)).diamondCut(cuts, address(0), "");
50+
console2.log("PolymerCCTPFacet successfully added to diamond");
51+
52+
vm.stopBroadcast();
53+
}
54+
}

0 commit comments

Comments
 (0)