Files
gru_emoney_token-factory/test/fuzz/TransferFuzz.t.sol
defiQUG 651ff4f7eb Initial project setup: Add contracts, API definitions, tests, and documentation
- Add Foundry project configuration (foundry.toml, foundry.lock)
- Add Solidity contracts (TokenFactory138, BridgeVault138, ComplianceRegistry, etc.)
- Add API definitions (OpenAPI, GraphQL, gRPC, AsyncAPI)
- Add comprehensive test suite (unit, integration, fuzz, invariants)
- Add API services (REST, GraphQL, orchestrator, packet service)
- Add documentation (ISO20022 mapping, runbooks, adapter guides)
- Add development tools (RBC tool, Swagger UI, mock server)
- Update OpenZeppelin submodules to v5.0.0
2025-12-12 10:59:41 -08:00

163 lines
5.5 KiB
Solidity

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import "forge-std/Test.sol";
import "../../src/eMoneyToken.sol";
import "../../src/PolicyManager.sol";
import "../../src/ComplianceRegistry.sol";
import "../../src/DebtRegistry.sol";
import "../../src/errors/TokenErrors.sol";
import "../../src/libraries/ReasonCodes.sol";
import "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol";
contract TransferFuzz is Test {
eMoneyToken public token;
PolicyManager public policyManager;
ComplianceRegistry public complianceRegistry;
DebtRegistry public debtRegistry;
address public admin;
address public issuer;
address public user1;
address public user2;
function setUp() public {
admin = address(0x1);
issuer = address(0x2);
user1 = address(0x10);
user2 = address(0x20);
complianceRegistry = new ComplianceRegistry(admin);
debtRegistry = new DebtRegistry(admin);
policyManager = new PolicyManager(admin, address(complianceRegistry), address(debtRegistry));
eMoneyToken implementation = new eMoneyToken();
bytes memory initData = abi.encodeWithSelector(
eMoneyToken.initialize.selector,
"Test Token",
"TEST",
18,
issuer,
address(policyManager),
address(debtRegistry),
address(complianceRegistry)
);
ERC1967Proxy proxy = new ERC1967Proxy(address(implementation), initData);
token = eMoneyToken(address(proxy));
vm.startPrank(admin);
policyManager.grantRole(policyManager.POLICY_OPERATOR_ROLE(), admin);
policyManager.setLienMode(address(token), 2); // Encumbered mode
complianceRegistry.grantRole(complianceRegistry.COMPLIANCE_ROLE(), admin);
complianceRegistry.setCompliance(user1, true, 1, bytes32(0));
complianceRegistry.setCompliance(user2, true, 1, bytes32(0));
debtRegistry.grantRole(debtRegistry.DEBT_AUTHORITY_ROLE(), admin);
vm.stopPrank();
}
function testFuzz_transferWithLien(
uint256 mintAmount,
uint256 lienAmount,
uint256 transferAmount
) public {
// Bound inputs to reasonable ranges
mintAmount = bound(mintAmount, 1, type(uint128).max);
lienAmount = bound(lienAmount, 0, mintAmount);
transferAmount = bound(transferAmount, 0, mintAmount);
// Mint to user1
vm.prank(issuer);
token.mint(user1, mintAmount, ReasonCodes.OK);
// Place lien
if (lienAmount > 0) {
vm.prank(admin);
debtRegistry.placeLien(user1, lienAmount, 0, 1, ReasonCodes.LIEN_BLOCK);
}
uint256 freeBalance = token.freeBalanceOf(user1);
bool shouldSucceed = transferAmount <= freeBalance && transferAmount > 0;
if (shouldSucceed) {
vm.prank(user1);
token.transfer(user2, transferAmount);
assertEq(token.balanceOf(user1), mintAmount - transferAmount);
assertEq(token.balanceOf(user2), transferAmount);
} else if (transferAmount > freeBalance && lienAmount > 0) {
// Should fail with insufficient free balance
vm.expectRevert();
vm.prank(user1);
token.transfer(user2, transferAmount);
}
}
function testFuzz_transferWithMultipleLiens(
uint256 mintAmount,
uint256[3] memory lienAmounts,
uint256 transferAmount
) public {
mintAmount = bound(mintAmount, 1000, type(uint128).max);
transferAmount = bound(transferAmount, 0, mintAmount);
// Bound lien amounts
for (uint256 i = 0; i < 3; i++) {
lienAmounts[i] = bound(lienAmounts[i], 0, mintAmount / 3);
}
// Mint to user1
vm.prank(issuer);
token.mint(user1, mintAmount, ReasonCodes.OK);
// Place multiple liens
uint256 totalLienAmount = 0;
for (uint256 i = 0; i < 3; i++) {
if (lienAmounts[i] > 0) {
vm.prank(admin);
debtRegistry.placeLien(user1, lienAmounts[i], 0, 1, ReasonCodes.LIEN_BLOCK);
totalLienAmount += lienAmounts[i];
}
}
uint256 freeBalance = mintAmount > totalLienAmount ? mintAmount - totalLienAmount : 0;
bool shouldSucceed = transferAmount <= freeBalance && transferAmount > 0;
if (shouldSucceed) {
vm.prank(user1);
token.transfer(user2, transferAmount);
assertEq(token.balanceOf(user1), mintAmount - transferAmount);
} else if (transferAmount > freeBalance && totalLienAmount > 0) {
vm.expectRevert();
vm.prank(user1);
token.transfer(user2, transferAmount);
}
}
function testFuzz_freeBalanceCalculation(
uint256 balance,
uint256 encumbrance
) public {
balance = bound(balance, 0, type(uint128).max);
encumbrance = bound(encumbrance, 0, type(uint128).max);
if (balance > 0) {
vm.prank(issuer);
token.mint(user1, balance, ReasonCodes.OK);
}
if (encumbrance > 0) {
vm.prank(admin);
debtRegistry.placeLien(user1, encumbrance, 0, 1, ReasonCodes.LIEN_BLOCK);
}
uint256 freeBalance = token.freeBalanceOf(user1);
uint256 expectedFreeBalance = balance > encumbrance ? balance - encumbrance : 0;
assertEq(freeBalance, expectedFreeBalance, "Free balance calculation incorrect");
}
}