Add Oracle Aggregator and CCIP Integration
- Introduced Aggregator.sol for Chainlink-compatible oracle functionality, including round-based updates and access control. - Added OracleWithCCIP.sol to extend Aggregator with CCIP cross-chain messaging capabilities. - Created .gitmodules to include OpenZeppelin contracts as a submodule. - Developed a comprehensive deployment guide in NEXT_STEPS_COMPLETE_GUIDE.md for Phase 2 and smart contract deployment. - Implemented Vite configuration for the orchestration portal, supporting both Vue and React frameworks. - Added server-side logic for the Multi-Cloud Orchestration Portal, including API endpoints for environment management and monitoring. - Created scripts for resource import and usage validation across non-US regions. - Added tests for CCIP error handling and integration to ensure robust functionality. - Included various new files and directories for the orchestration portal and deployment scripts.
This commit is contained in:
151
test/ccip-integration/CCIPIntegration.test.js
Normal file
151
test/ccip-integration/CCIPIntegration.test.js
Normal file
@@ -0,0 +1,151 @@
|
||||
const { expect } = require("chai");
|
||||
const { ethers } = require("hardhat");
|
||||
|
||||
describe("CCIP Integration", function () {
|
||||
let ccipLogger, ccipReporter;
|
||||
let owner, relayer;
|
||||
let mockRouter, mockSourceRouter;
|
||||
|
||||
beforeEach(async function () {
|
||||
[owner, relayer] = await ethers.getSigners();
|
||||
|
||||
// Deploy mock routers for testing
|
||||
// In production, these would be the actual Chainlink CCIP routers
|
||||
const MockRouter = await ethers.getContractFactory("MockCCIPRouter");
|
||||
mockRouter = await MockRouter.deploy();
|
||||
await mockRouter.waitForDeployment();
|
||||
|
||||
mockSourceRouter = await MockRouter.deploy();
|
||||
await mockSourceRouter.waitForDeployment();
|
||||
|
||||
// Deploy CCIPLogger (Ethereum receiver)
|
||||
const CCIPLogger = await ethers.getContractFactory("CCIPLogger");
|
||||
ccipLogger = await CCIPLogger.deploy(
|
||||
await mockRouter.getAddress(),
|
||||
ethers.ZeroAddress, // No authorized signer for basic test
|
||||
"0x000000000000008a" // Chain-138 selector
|
||||
);
|
||||
await ccipLogger.waitForDeployment();
|
||||
|
||||
// Deploy CCIPTxReporter (Chain-138 sender)
|
||||
const CCIPTxReporter = await ethers.getContractFactory("CCIPTxReporter");
|
||||
ccipReporter = await CCIPTxReporter.deploy(
|
||||
await mockSourceRouter.getAddress(),
|
||||
"0x500147", // Ethereum Mainnet selector
|
||||
await ccipLogger.getAddress()
|
||||
);
|
||||
await ccipReporter.waitForDeployment();
|
||||
});
|
||||
|
||||
describe("CCIPTxReporter", function () {
|
||||
it("Should report a single transaction", async function () {
|
||||
const txHash = ethers.keccak256(ethers.toUtf8Bytes("test-tx"));
|
||||
const fromAddr = owner.address;
|
||||
const toAddr = relayer.address;
|
||||
const value = ethers.parseEther("1.0");
|
||||
|
||||
await expect(
|
||||
ccipReporter.reportTx(txHash, fromAddr, toAddr, value, "0x", {
|
||||
value: ethers.parseEther("0.01"),
|
||||
})
|
||||
).to.emit(ccipReporter, "SingleTxReported");
|
||||
});
|
||||
|
||||
it("Should report a batch of transactions", async function () {
|
||||
const batchId = ethers.keccak256(ethers.toUtf8Bytes("test-batch"));
|
||||
const txHashes = [
|
||||
ethers.keccak256(ethers.toUtf8Bytes("tx1")),
|
||||
ethers.keccak256(ethers.toUtf8Bytes("tx2")),
|
||||
];
|
||||
const froms = [owner.address, relayer.address];
|
||||
const tos = [relayer.address, owner.address];
|
||||
const values = [ethers.parseEther("1.0"), ethers.parseEther("2.0")];
|
||||
|
||||
await expect(
|
||||
ccipReporter.reportBatch(batchId, txHashes, froms, tos, values, "0x", {
|
||||
value: ethers.parseEther("0.01"),
|
||||
})
|
||||
).to.emit(ccipReporter, "BatchReported");
|
||||
});
|
||||
|
||||
it("Should estimate fee correctly", async function () {
|
||||
const txHashes = [ethers.keccak256(ethers.toUtf8Bytes("tx1"))];
|
||||
const froms = [owner.address];
|
||||
const tos = [relayer.address];
|
||||
const values = [ethers.parseEther("1.0")];
|
||||
|
||||
const fee = await ccipReporter.estimateFee(
|
||||
txHashes,
|
||||
froms,
|
||||
tos,
|
||||
values,
|
||||
"0x"
|
||||
);
|
||||
|
||||
expect(fee).to.be.gt(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe("CCIPLogger", function () {
|
||||
it("Should receive and log transactions", async function () {
|
||||
const batchId = ethers.keccak256(ethers.toUtf8Bytes("test-batch"));
|
||||
const txHashes = [ethers.keccak256(ethers.toUtf8Bytes("tx1"))];
|
||||
const froms = [owner.address];
|
||||
const tos = [relayer.address];
|
||||
const values = [ethers.parseEther("1.0")];
|
||||
|
||||
const payload = ethers.AbiCoder.defaultAbiCoder().encode(
|
||||
["bytes32", "bytes32[]", "address[]", "address[]", "uint256[]", "bytes"],
|
||||
[batchId, txHashes, froms, tos, values, "0x"]
|
||||
);
|
||||
|
||||
// Simulate CCIP message delivery
|
||||
const message = {
|
||||
messageId: ethers.keccak256(ethers.toUtf8Bytes("test-message")),
|
||||
sourceChainSelector: "0x000000000000008a",
|
||||
sender: await ccipReporter.getAddress(),
|
||||
data: payload,
|
||||
destTokenAmounts: [],
|
||||
};
|
||||
|
||||
await expect(
|
||||
mockRouter.deliverMessage(await ccipLogger.getAddress(), message)
|
||||
).to.emit(ccipLogger, "RemoteBatchLogged");
|
||||
});
|
||||
|
||||
it("Should prevent replay attacks", async function () {
|
||||
const batchId = ethers.keccak256(ethers.toUtf8Bytes("replay-test"));
|
||||
const txHashes = [ethers.keccak256(ethers.toUtf8Bytes("tx1"))];
|
||||
const froms = [owner.address];
|
||||
const tos = [relayer.address];
|
||||
const values = [ethers.parseEther("1.0")];
|
||||
|
||||
const payload = ethers.AbiCoder.defaultAbiCoder().encode(
|
||||
["bytes32", "bytes32[]", "address[]", "address[]", "uint256[]", "bytes"],
|
||||
[batchId, txHashes, froms, tos, values, "0x"]
|
||||
);
|
||||
|
||||
const message = {
|
||||
messageId: ethers.keccak256(ethers.toUtf8Bytes("test-message-1")),
|
||||
sourceChainSelector: "0x000000000000008a",
|
||||
sender: await ccipReporter.getAddress(),
|
||||
data: payload,
|
||||
destTokenAmounts: [],
|
||||
};
|
||||
|
||||
// First delivery should succeed
|
||||
await mockRouter.deliverMessage(await ccipLogger.getAddress(), message);
|
||||
|
||||
// Second delivery with same batchId should fail
|
||||
const message2 = {
|
||||
...message,
|
||||
messageId: ethers.keccak256(ethers.toUtf8Bytes("test-message-2")),
|
||||
};
|
||||
|
||||
await expect(
|
||||
mockRouter.deliverMessage(await ccipLogger.getAddress(), message2)
|
||||
).to.be.revertedWith("CCIPLogger: batch already processed");
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user