feat: bridges, PMM, flash workflow, token-aggregation, and deployment docs

- CCIP/trustless bridge contracts, GRU tokens, DEX/PMM tests, reserve vault.
- Token-aggregation service routes, planner, chain config, relay env templates.
- Config snapshots and multi-chain deployment markdown updates.
- gitignore services/btc-intake/dist/ (tsc output); do not track dist.

Run forge build && forge test before deploy (large solc graph).

Made-with: Cursor
This commit is contained in:
defiQUG
2026-04-07 23:40:52 -07:00
parent 0fb7bba07b
commit 76aa419320
289 changed files with 28367 additions and 824 deletions

View File

@@ -14,6 +14,12 @@ contract CompliantFiatTokenV2Test is Test {
keccak256(
"TransferWithAuthorization(address from,address to,uint256 value,uint256 validAfter,uint256 validBefore,bytes32 nonce)"
);
bytes32 private constant RECEIVE_WITH_AUTHORIZATION_TYPEHASH =
keccak256(
"ReceiveWithAuthorization(address from,address to,uint256 value,uint256 validAfter,uint256 validBefore,bytes32 nonce)"
);
bytes32 private constant CANCEL_AUTHORIZATION_TYPEHASH =
keccak256("CancelAuthorization(address authorizer,bytes32 nonce)");
event CompliantOperationDeclared(
bytes32 indexed operationType,
@@ -117,6 +123,89 @@ contract CompliantFiatTokenV2Test is Test {
assertTrue(token.authorizationState(owner, nonce));
}
function testReceiveWithAuthorizationRequiresPayeeCallerAndWorks() public {
uint256 value = 7_500 * 10 ** 6;
uint256 validAfter = block.timestamp - 1;
uint256 validBefore = block.timestamp + 1 days;
bytes32 nonce = keccak256("receive-auth-1");
bytes32 structHash = keccak256(
abi.encode(
RECEIVE_WITH_AUTHORIZATION_TYPEHASH,
owner,
recipient,
value,
validAfter,
validBefore,
nonce
)
);
bytes32 digest = keccak256(
abi.encodePacked("\x19\x01", token.DOMAIN_SEPARATOR(), structHash)
);
(uint8 v, bytes32 r, bytes32 s) = vm.sign(ownerPk, digest);
vm.prank(spender);
vm.expectRevert(
abi.encodeWithSelector(
CompliantFiatTokenV2.AuthorizationMustBeUsedByPayee.selector,
recipient,
spender
)
);
token.receiveWithAuthorization(owner, recipient, value, validAfter, validBefore, nonce, v, r, s);
vm.prank(recipient);
token.receiveWithAuthorization(owner, recipient, value, validAfter, validBefore, nonce, v, r, s);
assertEq(token.balanceOf(recipient), value);
assertTrue(token.authorizationState(owner, nonce));
}
function testCancelAuthorizationBlocksFutureUse() public {
uint256 value = 1_000 * 10 ** 6;
uint256 validAfter = block.timestamp - 1;
uint256 validBefore = block.timestamp + 1 days;
bytes32 nonce = keccak256("cancel-auth-1");
bytes32 cancelStructHash = keccak256(
abi.encode(CANCEL_AUTHORIZATION_TYPEHASH, owner, nonce)
);
bytes32 cancelDigest = keccak256(
abi.encodePacked("\x19\x01", token.DOMAIN_SEPARATOR(), cancelStructHash)
);
(uint8 cancelV, bytes32 cancelR, bytes32 cancelS) = vm.sign(ownerPk, cancelDigest);
token.cancelAuthorization(owner, nonce, cancelV, cancelR, cancelS);
assertTrue(token.authorizationState(owner, nonce));
bytes32 transferStructHash = keccak256(
abi.encode(
TRANSFER_WITH_AUTHORIZATION_TYPEHASH,
owner,
recipient,
value,
validAfter,
validBefore,
nonce
)
);
bytes32 transferDigest = keccak256(
abi.encodePacked("\x19\x01", token.DOMAIN_SEPARATOR(), transferStructHash)
);
(uint8 v, bytes32 r, bytes32 s) = vm.sign(ownerPk, transferDigest);
vm.prank(spender);
vm.expectRevert(
abi.encodeWithSelector(
CompliantFiatTokenV2.AuthorizationAlreadyUsed.selector,
owner,
nonce
)
);
token.transferWithAuthorization(owner, recipient, value, validAfter, validBefore, nonce, v, r, s);
}
function testMintAndBurnReasonHashesEmitStructuredEvents() public {
bytes32 mintReason = keccak256("mint-reason");
bytes32 burnReason = keccak256("burn-reason");
@@ -245,6 +334,26 @@ contract CompliantFiatTokenV2Test is Test {
assertFalse(token.wrappedTransport());
}
function testEip5267DomainIntrospectionMatchesTokenMetadata() public view {
(
bytes1 fields,
string memory name,
string memory version,
uint256 chainId,
address verifyingContract,
bytes32 salt,
uint256[] memory extensions
) = token.eip712Domain();
assertEq(uint8(fields), uint8(0x0f));
assertEq(name, "Euro Coin (Compliant V2)");
assertEq(version, "2");
assertEq(chainId, block.chainid);
assertEq(verifyingContract, address(token));
assertEq(salt, bytes32(0));
assertEq(extensions.length, 0);
}
function testEmergencyMetadataOverridesRemainAvailableOutsideGovernance() public {
vm.prank(admin);
token.emergencySetPresentationMetadata(true, "ipfs://emergency-token", "cEURC-emergency");

View File

@@ -0,0 +1,54 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import {Test} from "forge-std/Test.sol";
import {CompliantBTC} from "../../contracts/tokens/CompliantBTC.sol";
contract CompliantMonetaryUnitTokenTest is Test {
CompliantBTC public token;
address public owner;
address public admin;
address public user1;
function setUp() public {
owner = address(this);
admin = address(this);
user1 = address(0xB0B);
token = new CompliantBTC(owner, admin, 21_000_000 * 10**8);
}
function testDecimals() public view {
assertEq(token.decimals(), 8);
}
function testUnitCode() public view {
assertEq(token.unitCode(), "BTC");
assertTrue(token.isMonetaryUnit());
}
function testInitialSupplyUsesSatoshiPrecision() public view {
assertEq(token.totalSupply(), 21_000_000 * 10**8);
assertEq(token.balanceOf(owner), 21_000_000 * 10**8);
}
function testTransferUsesEightDecimals() public {
uint256 amount = 12_500_000;
token.transfer(user1, amount);
assertEq(token.balanceOf(user1), amount);
assertEq(token.balanceOf(owner), 21_000_000 * 10**8 - amount);
}
function testPauseBlocksTransfers() public {
token.pause();
assertTrue(token.paused());
vm.expectRevert();
token.transfer(user1, 100_000_000);
}
function testMintAndBurnUseSatoshiPrecision() public {
token.mint(user1, 250_000_000);
assertEq(token.balanceOf(user1), 250_000_000);
token.burn(100_000_000);
assertEq(token.balanceOf(owner), 21_000_000 * 10**8 - 100_000_000);
}
}

View File

@@ -134,4 +134,24 @@ contract CompliantWrappedTokenTest is Test {
assertEq(token.reportingURI(), "ipfs://cw-emergency-reporting");
assertEq(token.minimumUpgradeNoticePeriod(), 30 days);
}
function testWrappedBTCCanUseEightDecimalsAndFrozenBridgeRoles() public {
CompliantWrappedToken wrappedBtc = new CompliantWrappedToken("Wrapped cBTC", "cWBTC", 8, admin);
wrappedBtc.grantRole(MINTER_ROLE, bridge);
wrappedBtc.grantRole(BURNER_ROLE, bridge);
vm.prank(bridge);
wrappedBtc.mint(user1, 125_000_000);
assertEq(wrappedBtc.decimals(), 8);
assertEq(wrappedBtc.balanceOf(user1), 125_000_000);
wrappedBtc.freezeOperationalRoles();
vm.prank(bridge);
wrappedBtc.burnFrom(user1, 25_000_000);
assertEq(wrappedBtc.balanceOf(user1), 100_000_000);
vm.expectRevert();
wrappedBtc.grantRole(MINTER_ROLE, address(0xCAFE));
}
}