Address
- Address
- 0xce11fbd4a8f246920630d589a421269a5f6073af
- Type
- contract
- Balance
- 0 tMIDX (0 wei)
- Nonce
- 1
- Code size
- 2,473 bytes
Contract
Source code ✓ verified
- Contract
- FxSettlement
- Compiler
- solc 0.8.36+commit.8a079791
- Optimizer
- enabled, 200 runs
- Verified
- 2026-09-22 19:33:34 UTC
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
interface IERC20 {
function transferFrom(address from, address to, uint256 value) external returns (bool);
}
/// @title FxSettlement
/// @notice Settles an FX fill from the MIDX maker as TWO real ERC-20 transfers -- the base leg and the
/// quote leg -- between the maker wallet and a taker wallet, atomically in one transaction, and
/// emits a paired `Settled` event. This is what makes the mock stablecoins behave as a PAIR: a
/// USD/MXN buy moves USDC one way and MXNB the other, and both token contracts log a Transfer.
///
/// Both wallets pre-approve this contract once (allowance), so at runtime only the owner (the
/// maker's signer key) submits `settle`; the contract pulls each leg with `transferFrom`. If either
/// leg fails the whole settlement reverts -- there are no half-settled trades. It custodies nothing.
///
/// Conventions match FxTradeRecorder: `side` is the TAKER side (1 = taker buys base, 2 = taker
/// sells base); `priceE8` is the rate scaled by 1e8; amounts are in each token's own base units.
/// Testnet only.
contract FxSettlement {
address public owner;
address public maker;
uint256 public settleCount;
struct Fill {
bytes32 clOrdId;
string symbol; // e.g. "USD/MXN"
uint8 side; // taker side: 1 = buy base, 2 = sell base
address baseToken;
uint256 baseAmount; // base token units
address quoteToken;
uint256 quoteAmount; // quote token units
uint256 priceE8;
address taker;
}
// Kept to 10 values: one more and solc 0.8.x hits "stack too deep" without viaIR, which the explorer's
// verifier does not use. execId / FIX time are omitted: clOrdId identifies the order and the block
// timestamp is on the transaction.
event Settled(
uint256 indexed seq,
bytes32 indexed clOrdId,
string symbol,
uint8 side,
address baseToken,
uint256 baseAmount,
address quoteToken,
uint256 quoteAmount,
uint256 priceE8,
address taker
);
event MakerChanged(address indexed previousMaker, address indexed newMaker);
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
modifier onlyOwner() {
require(msg.sender == owner, "not owner");
_;
}
constructor(address _owner, address _maker) {
require(_owner != address(0) && _maker != address(0), "zero address");
owner = _owner;
maker = _maker;
emit OwnershipTransferred(address(0), _owner);
emit MakerChanged(address(0), _maker);
}
/// @notice Settle one fill: move the base leg and the quote leg in opposite directions.
function settle(Fill calldata f) external onlyOwner {
require(f.side == 1 || f.side == 2, "bad side");
require(f.taker != address(0), "zero taker");
if (f.side == 1) {
// Taker buys base: maker delivers base, taker pays quote.
require(IERC20(f.baseToken).transferFrom(maker, f.taker, f.baseAmount), "base leg");
require(IERC20(f.quoteToken).transferFrom(f.taker, maker, f.quoteAmount), "quote leg");
} else {
// Taker sells base: taker delivers base, maker pays quote.
require(IERC20(f.baseToken).transferFrom(f.taker, maker, f.baseAmount), "base leg");
require(IERC20(f.quoteToken).transferFrom(maker, f.taker, f.quoteAmount), "quote leg");
}
emit Settled(++settleCount, f.clOrdId, f.symbol, f.side, f.baseToken, f.baseAmount,
f.quoteToken, f.quoteAmount, f.priceE8, f.taker);
}
function setMaker(address newMaker) external onlyOwner {
require(newMaker != address(0), "zero maker");
emit MakerChanged(maker, newMaker);
maker = newMaker;
}
function transferOwnership(address newOwner) external onlyOwner {
require(newOwner != address(0), "zero owner");
emit OwnershipTransferred(owner, newOwner);
owner = newOwner;
}
}
ABI
[
{
"type": "constructor",
"inputs": [
{
"name": "_owner",
"type": "address",
"internalType": "address"
},
{
"name": "_maker",
"type": "address",
"internalType": "address"
}
],
"stateMutability": "nonpayable"
},
{
"name": "MakerChanged",
"type": "event",
"inputs": [
{
"name": "previousMaker",
"type": "address",
"indexed": true,
"internalType": "address"
},
{
"name": "newMaker",
"type": "address",
"indexed": true,
"internalType": "address"
}
],
"anonymous": false
},
{
"name": "OwnershipTransferred",
"type": "event",
"inputs": [
{
"name": "previousOwner",
"type": "address",
"indexed": true,
"internalType": "address"
},
{
"name": "newOwner",
"type": "address",
"indexed": true,
"internalType": "address"
}
],
"anonymous": false
},
{
"name": "Settled",
"type": "event",
"inputs": [
{
"name": "seq",
"type": "uint256",
"indexed": true,
"internalType": "uint256"
},
{
"name": "clOrdId",
"type": "bytes32",
"indexed": true,
"internalType": "bytes32"
},
{
"name": "symbol",
"type": "string",
"indexed": false,
"internalType": "string"
},
{
"name": "side",
"type": "uint8",
"indexed": false,
"internalType": "uint8"
},
{
"name": "baseToken",
"type": "address",
"indexed": false,
"internalType": "address"
},
{
"name": "baseAmount",
"type": "uint256",
"indexed": false,
"internalType": "uint256"
},
{
"name": "quoteToken",
"type": "address",
"indexed": false,
"internalType": "address"
},
{
"name": "quoteAmount",
"type": "uint256",
"indexed": false,
"internalType": "uint256"
},
{
"name": "priceE8",
"type": "uint256",
"indexed": false,
"internalType": "uint256"
},
{
"name": "taker",
"type": "address",
"indexed": false,
"internalType": "address"
}
],
"anonymous": false
},
{
"name": "maker",
"type": "function",
"inputs": [],
"outputs": [
{
"name": "",
"type": "address",
"internalType": "address"
}
],
"stateMutability": "view"
},
{
"name": "owner",
"type": "function",
"inputs": [],
"outputs": [
{
"name": "",
"type": "address",
"internalType": "address"
}
],
"stateMutability": "view"
},
{
"name": "setMaker",
"type": "function",
"inputs": [
{
"name": "newMaker",
"type": "address",
"internalType": "address"
}
],
"outputs": [],
"stateMutability": "nonpayable"
},
{
"name": "settle",
"type": "function",
"inputs": [
{
"name": "f",
"type": "tuple",
"components": [
{
"name": "clOrdId",
"type": "bytes32",
"internalType": "bytes32"
},
{
"name": "symbol",
"type": "string",
"internalType": "string"
},
{
"name": "side",
"type": "uint8",
"internalType": "uint8"
},
{
"name": "baseToken",
"type": "address",
"internalType": "address"
},
{
"name": "baseAmount",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "quoteToken",
"type": "address",
"internalType": "address"
},
{
"name": "quoteAmount",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "priceE8",
"type": "uint256",
"internalType": "uint256"
},
{
"name": "taker",
"type": "address",
"internalType": "address"
}
],
"internalType": "struct FxSettlement.Fill"
}
],
"outputs": [],
"stateMutability": "nonpayable"
},
{
"name": "settleCount",
"type": "function",
"inputs": [],
"outputs": [
{
"name": "",
"type": "uint256",
"internalType": "uint256"
}
],
"stateMutability": "view"
},
{
"name": "transferOwnership",
"type": "function",
"inputs": [
{
"name": "newOwner",
"type": "address",
"internalType": "address"
}
],
"outputs": [],
"stateMutability": "nonpayable"
}
]Transactions (5 indexed)
page 1 / 1
Temporary placeholder infrastructure for chain registration.
Not a production network - state may be reset without notice.