Files
smom-dbis-138/contracts/dbis/DBIS_ConversionRouter.sol
defiQUG 1511f33857 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
2026-03-04 02:00:09 -08:00

183 lines
6.6 KiB
Solidity

// SPDX-License-Identifier: MIT
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";
interface IBlocklist {
function isBlocked(address account) external view returns (bool);
}
struct SwapAuth {
bytes32 messageId;
bytes32 lpaId;
bytes32 venue;
address tokenIn;
address tokenOut;
uint256 amountIn;
uint256 minAmountOut;
uint256 deadline;
bytes32 quoteHash;
address quoteIssuer;
uint256 chainId;
address verifyingContract;
}
contract DBIS_ConversionRouter is AccessControl, Pausable, ReentrancyGuard {
bytes32 public constant ROUTER_ADMIN_ROLE = keccak256("ROUTER_ADMIN");
uint256 public constant CHAIN_ID = 138;
bytes32 public constant SIGNER_REGISTRY_KEY = keccak256("SignerRegistry");
bytes32 public constant STABLECOIN_REGISTRY_KEY = keccak256("StablecoinReferenceRegistry");
bytes32 private constant EIP712_DOMAIN_TYPEHASH = keccak256(
"EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"
);
bytes32 private constant SWAPAUTH_TYPEHASH = keccak256(
"SwapAuth(bytes32 messageId,bytes32 lpaId,bytes32 venue,address tokenIn,address tokenOut,uint256 amountIn,uint256 minAmountOut,uint256 deadline,bytes32 quoteHash,address quoteIssuer,uint256 chainId,address verifyingContract)"
);
DBIS_RootRegistry public rootRegistry;
address public eip712Helper;
mapping(bytes32 => bool) public usedSwapMessageIds;
mapping(bytes32 => bool) public venueAllowlist;
mapping(address => bool) public quoteIssuerAllowlist;
address public blocklistContract;
event ConversionExecuted(
bytes32 indexed messageId,
bytes32 indexed quoteHash,
bytes32 venue,
address tokenIn,
address tokenOut,
uint256 amountIn,
uint256 amountOut,
address quoteIssuer
);
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) {
venueAllowlist[venue] = true;
}
function removeVenue(bytes32 venue) external onlyRole(ROUTER_ADMIN_ROLE) {
venueAllowlist[venue] = false;
}
function addQuoteIssuer(address issuer) external onlyRole(ROUTER_ADMIN_ROLE) {
quoteIssuerAllowlist[issuer] = true;
}
function removeQuoteIssuer(address issuer) external onlyRole(ROUTER_ADMIN_ROLE) {
quoteIssuerAllowlist[issuer] = false;
}
function setBlocklist(address _blocklist) external onlyRole(ROUTER_ADMIN_ROLE) {
blocklistContract = _blocklist;
}
function pause() external onlyRole(ROUTER_ADMIN_ROLE) {
_pause();
}
function unpause() external onlyRole(ROUTER_ADMIN_ROLE) {
_unpause();
}
function _domainSeparator() private view returns (bytes32) {
return keccak256(
abi.encode(
EIP712_DOMAIN_TYPEHASH,
keccak256("DBISConversionRouter"),
keccak256("1"),
CHAIN_ID,
address(this)
)
);
}
function getSwapAuthDigest(SwapAuth calldata auth) external view returns (bytes32) {
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 {
require(auth.chainId == CHAIN_ID, "DBIS: wrong chain");
require(auth.verifyingContract == address(this), "DBIS: wrong contract");
require(block.timestamp <= auth.deadline, "DBIS: expired");
require(!usedSwapMessageIds[auth.messageId], "DBIS: replay");
require(venueAllowlist[auth.venue], "DBIS: venue not allowed");
require(quoteIssuerAllowlist[auth.quoteIssuer], "DBIS: quote issuer not allowed");
require(amountOut >= auth.minAmountOut, "DBIS: slippage");
_requireStablecoinActive(auth.tokenOut);
_requireNotBlocked();
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(
auth.messageId,
auth.quoteHash,
auth.venue,
auth.tokenIn,
auth.tokenOut,
auth.amountIn,
amountOut,
auth.quoteIssuer
);
}
function _requireStablecoinActive(address tokenOut) private view {
StablecoinReferenceRegistry stableReg = StablecoinReferenceRegistry(rootRegistry.getComponent(STABLECOIN_REGISTRY_KEY));
if (address(stableReg) != address(0)) require(stableReg.isActive(tokenOut), "DBIS: tokenOut not active");
}
function _requireNotBlocked() private view {
if (blocklistContract != address(0)) require(!IBlocklist(blocklistContract).isBlocked(msg.sender), "DBIS: blocked");
}
}