chore: update DBIS contracts and integrate EIP-712 helper

- Updated DBIS_ConversionRouter and DBIS_SettlementRouter to utilize IDBIS_EIP712Helper for EIP-712 hashing and signature recovery, improving stack depth management.
- Refactored minting logic in DBIS_GRU_MintController to streamline recipient processing.
- Enhanced BUILD_NOTES.md with updated build instructions and test coverage details.
- Added new functions in DBIS_SignerRegistry for duplicate signer checks and active signer validation.
- Introduced a new submodule, DBIS_EIP712Helper, to encapsulate EIP-712 related functionalities.

Made-with: Cursor
This commit is contained in:
defiQUG
2026-03-04 02:00:09 -08:00
parent 51b9b7458b
commit 1511f33857
50 changed files with 1315 additions and 272 deletions

View File

@@ -4,6 +4,7 @@ pragma solidity ^0.8.20;
import "@openzeppelin/contracts/access/AccessControl.sol";
import "@openzeppelin/contracts/utils/Pausable.sol";
import "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
import "./IDBIS_EIP712Helper.sol";
import "./DBIS_RootRegistry.sol";
import "./DBIS_SignerRegistry.sol";
import "./StablecoinReferenceRegistry.sol";
@@ -42,6 +43,7 @@ contract DBIS_ConversionRouter is AccessControl, Pausable, ReentrancyGuard {
);
DBIS_RootRegistry public rootRegistry;
address public eip712Helper;
mapping(bytes32 => bool) public usedSwapMessageIds;
mapping(bytes32 => bool) public venueAllowlist;
mapping(address => bool) public quoteIssuerAllowlist;
@@ -58,10 +60,11 @@ contract DBIS_ConversionRouter is AccessControl, Pausable, ReentrancyGuard {
address quoteIssuer
);
constructor(address admin, address _rootRegistry) {
constructor(address admin, address _rootRegistry, address _eip712Helper) {
_grantRole(DEFAULT_ADMIN_ROLE, admin);
_grantRole(ROUTER_ADMIN_ROLE, admin);
rootRegistry = DBIS_RootRegistry(_rootRegistry);
eip712Helper = _eip712Helper;
}
function addVenue(bytes32 venue) external onlyRole(ROUTER_ADMIN_ROLE) {
@@ -104,28 +107,23 @@ contract DBIS_ConversionRouter is AccessControl, Pausable, ReentrancyGuard {
);
}
function _hashSwapAuth(SwapAuth calldata auth) private pure returns (bytes32) {
return keccak256(
abi.encode(
SWAPAUTH_TYPEHASH,
auth.messageId,
auth.lpaId,
auth.venue,
auth.tokenIn,
auth.tokenOut,
auth.amountIn,
auth.minAmountOut,
auth.deadline,
auth.quoteHash,
auth.quoteIssuer,
auth.chainId,
auth.verifyingContract
)
);
}
function getSwapAuthDigest(SwapAuth calldata auth) external view returns (bytes32) {
return keccak256(abi.encodePacked("\x19\x01", _domainSeparator(), _hashSwapAuth(auth)));
return IDBIS_EIP712Helper(eip712Helper).getSwapAuthDigest(
_domainSeparator(),
SWAPAUTH_TYPEHASH,
auth.messageId,
auth.lpaId,
auth.venue,
auth.tokenIn,
auth.tokenOut,
auth.amountIn,
auth.minAmountOut,
auth.deadline,
auth.quoteHash,
auth.quoteIssuer,
auth.chainId,
auth.verifyingContract
);
}
function submitSwapAuth(SwapAuth calldata auth, bytes[] calldata signatures, uint256 amountOut) external nonReentrant whenNotPaused {
@@ -138,9 +136,26 @@ contract DBIS_ConversionRouter is AccessControl, Pausable, ReentrancyGuard {
require(amountOut >= auth.minAmountOut, "DBIS: slippage");
_requireStablecoinActive(auth.tokenOut);
_requireNotBlocked();
address[] memory signers = _recoverSwapSigners(auth, signatures);
DBIS_SignerRegistry signerReg = DBIS_SignerRegistry(rootRegistry.getComponent(SIGNER_REGISTRY_KEY));
(bool ok, ) = signerReg.validateSignersForSwap(signers, auth.amountIn);
bytes32 digest = IDBIS_EIP712Helper(eip712Helper).getSwapAuthDigest(
_domainSeparator(),
SWAPAUTH_TYPEHASH,
auth.messageId,
auth.lpaId,
auth.venue,
auth.tokenIn,
auth.tokenOut,
auth.amountIn,
auth.minAmountOut,
auth.deadline,
auth.quoteHash,
auth.quoteIssuer,
auth.chainId,
auth.verifyingContract
);
address[] memory signers = IDBIS_EIP712Helper(eip712Helper).recoverSigners(digest, signatures);
require(!DBIS_SignerRegistry(rootRegistry.getComponent(SIGNER_REGISTRY_KEY)).hasDuplicateSigners(signers), "DBIS: duplicate signer");
require(DBIS_SignerRegistry(rootRegistry.getComponent(SIGNER_REGISTRY_KEY)).areSignersActiveAtBlock(signers, block.number), "DBIS: signer not active");
(bool ok, ) = DBIS_SignerRegistry(rootRegistry.getComponent(SIGNER_REGISTRY_KEY)).validateSignersForSwap(signers, auth.amountIn);
require(ok, "DBIS: quorum not met");
usedSwapMessageIds[auth.messageId] = true;
emit ConversionExecuted(
@@ -164,33 +179,4 @@ contract DBIS_ConversionRouter is AccessControl, Pausable, ReentrancyGuard {
if (blocklistContract != address(0)) require(!IBlocklist(blocklistContract).isBlocked(msg.sender), "DBIS: blocked");
}
function _recoverSwapSigners(SwapAuth calldata auth, bytes[] calldata signatures) private view returns (address[] memory signers) {
DBIS_SignerRegistry signerReg = DBIS_SignerRegistry(rootRegistry.getComponent(SIGNER_REGISTRY_KEY));
require(address(signerReg) != address(0), "DBIS: no signer registry");
bytes32 digest = keccak256(abi.encodePacked("\x19\x01", _domainSeparator(), _hashSwapAuth(auth)));
signers = new address[](signatures.length);
for (uint256 i = 0; i < signatures.length; i++) {
require(signatures[i].length == 65, "DBIS: bad sig len");
address signer = _recover(digest, signatures[i]);
require(signer != address(0), "DBIS: invalid sig");
require(signerReg.isSignerActiveAtBlock(signer, block.number), "DBIS: signer not active");
for (uint256 j = 0; j < i; j++) require(signers[j] != signer, "DBIS: duplicate signer");
signers[i] = signer;
}
}
function _recover(bytes32 digest, bytes calldata signature) private pure returns (address) {
require(signature.length == 65, "DBIS: sig length");
bytes32 r;
bytes32 s;
uint8 v;
assembly {
r := calldataload(signature.offset)
s := calldataload(add(signature.offset, 32))
v := byte(0, calldataload(add(signature.offset, 64)))
}
if (v < 27) v += 27;
require(v == 27 || v == 28, "DBIS: invalid v");
return ecrecover(digest, v, r, s);
}
}