125 lines
4.3 KiB
Solidity
125 lines
4.3 KiB
Solidity
// SPDX-License-Identifier: MIT
|
|
pragma solidity ^0.8.20;
|
|
|
|
import "forge-std/Test.sol";
|
|
import "../../contracts/iso4217w/oracle/ReserveOracle.sol";
|
|
|
|
contract ReserveOracleTest is Test {
|
|
ReserveOracle public oracle;
|
|
|
|
address public admin = address(0x1);
|
|
address public oracle1 = address(0x2);
|
|
address public oracle2 = address(0x3);
|
|
address public oracle3 = address(0x4);
|
|
|
|
string public constant CURRENCY_CODE = "USD";
|
|
|
|
uint256 public constant STALENESS_THRESHOLD = 3600; // 1 hour
|
|
uint256 public constant QUORUM_SIZE = 3;
|
|
|
|
function setUp() public {
|
|
vm.warp(STALENESS_THRESHOLD + 1); // Avoid underflow: block.timestamp - stalenessThreshold
|
|
vm.startPrank(admin);
|
|
oracle = new ReserveOracle(admin, QUORUM_SIZE, STALENESS_THRESHOLD);
|
|
|
|
// Add oracles (also grants ORACLE_ROLE)
|
|
oracle.addOracle(oracle1);
|
|
oracle.addOracle(oracle2);
|
|
oracle.addOracle(oracle3);
|
|
|
|
vm.stopPrank();
|
|
}
|
|
|
|
function test_SubmitReserveReport() public {
|
|
uint256 reserve = 10000e2;
|
|
bytes32 attestationHash = keccak256("attestation");
|
|
|
|
// Submit from all 3 oracles to reach quorum (QUORUM_SIZE=3)
|
|
vm.prank(oracle1);
|
|
oracle.submitReserveReport(CURRENCY_CODE, reserve, attestationHash);
|
|
vm.prank(oracle2);
|
|
oracle.submitReserveReport(CURRENCY_CODE, reserve, attestationHash);
|
|
vm.prank(oracle3);
|
|
oracle.submitReserveReport(CURRENCY_CODE, reserve, attestationHash);
|
|
|
|
(uint256 verifiedReserve, uint256 timestamp) = oracle.getVerifiedReserve(CURRENCY_CODE);
|
|
assertEq(verifiedReserve, reserve);
|
|
assertGt(timestamp, 0);
|
|
}
|
|
|
|
function test_GetVerifiedReserve_Quorum() public {
|
|
// Submit reports from all 3 oracles
|
|
uint256 reserve = 10000e2;
|
|
bytes32 attestationHash = keccak256("attestation");
|
|
|
|
vm.prank(oracle1);
|
|
oracle.submitReserveReport(CURRENCY_CODE, reserve, attestationHash);
|
|
|
|
vm.prank(oracle2);
|
|
oracle.submitReserveReport(CURRENCY_CODE, reserve, attestationHash);
|
|
|
|
vm.prank(oracle3);
|
|
oracle.submitReserveReport(CURRENCY_CODE, reserve, attestationHash);
|
|
|
|
(uint256 verifiedReserve, ) = oracle.getVerifiedReserve(CURRENCY_CODE);
|
|
|
|
// Should get consensus (all same)
|
|
assertEq(verifiedReserve, reserve);
|
|
}
|
|
|
|
function test_IsQuorumMet() public {
|
|
uint256 reserve = 10000e2;
|
|
bytes32 attestationHash = keccak256("attestation");
|
|
|
|
// Submit from 2 oracles (not quorum yet)
|
|
vm.prank(oracle1);
|
|
oracle.submitReserveReport(CURRENCY_CODE, reserve, attestationHash);
|
|
|
|
vm.prank(oracle2);
|
|
oracle.submitReserveReport(CURRENCY_CODE, reserve, attestationHash);
|
|
|
|
(bool quorum1, ) = oracle.isQuorumMet(CURRENCY_CODE);
|
|
assertFalse(quorum1, "Should not have quorum with 2/3");
|
|
|
|
// Submit from third oracle
|
|
vm.prank(oracle3);
|
|
oracle.submitReserveReport(CURRENCY_CODE, reserve, attestationHash);
|
|
|
|
(bool quorum2, ) = oracle.isQuorumMet(CURRENCY_CODE);
|
|
assertTrue(quorum2, "Should have quorum with 3/3");
|
|
}
|
|
|
|
function test_RemoveStaleReports() public {
|
|
uint256 reserve = 10000e2;
|
|
bytes32 attestationHash = keccak256("attestation");
|
|
|
|
vm.prank(oracle1);
|
|
oracle.submitReserveReport(CURRENCY_CODE, reserve, attestationHash);
|
|
|
|
// Fast forward time to make reports stale
|
|
vm.warp(block.timestamp + STALENESS_THRESHOLD + 1);
|
|
|
|
// Stale reports should not count towards quorum
|
|
(bool quorum, ) = oracle.isQuorumMet(CURRENCY_CODE);
|
|
assertFalse(quorum, "Stale reports should not count");
|
|
}
|
|
|
|
function test_GetConsensusReserve() public {
|
|
bytes32 attestationHash = keccak256("attestation");
|
|
|
|
// Submit different reports
|
|
vm.prank(oracle1);
|
|
oracle.submitReserveReport(CURRENCY_CODE, 10000e2, attestationHash);
|
|
|
|
vm.prank(oracle2);
|
|
oracle.submitReserveReport(CURRENCY_CODE, 10001e2, attestationHash); // 1 USD difference
|
|
|
|
vm.prank(oracle3);
|
|
oracle.submitReserveReport(CURRENCY_CODE, 9999e2, attestationHash); // 1 USD difference
|
|
|
|
// Consensus should be median or average
|
|
uint256 consensus = oracle.getConsensusReserve(CURRENCY_CODE);
|
|
assertGt(consensus, 0, "Should have consensus value");
|
|
}
|
|
}
|