- Expand token-aggregation API (report routes), canonical tokens, pools - Add flash vault contracts + tests (indexed, DODO cwUSDC, XAUT borrow) - PMM pools JSON, deploy/export scripts, metamask verified list Co-authored-by: Cursor <cursoragent@cursor.com>
88 lines
3.3 KiB
Solidity
88 lines
3.3 KiB
Solidity
// SPDX-License-Identifier: MIT
|
|
pragma solidity ^0.8.20;
|
|
|
|
import {IERC3156FlashBorrower} from "@openzeppelin/contracts/interfaces/IERC3156FlashBorrower.sol";
|
|
import {IERC3156FlashLender} from "@openzeppelin/contracts/interfaces/IERC3156FlashLender.sol";
|
|
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
|
|
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
|
|
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
|
|
|
|
/// @notice Minimal Engine X ERC-3156 borrower for proving same-transaction USDC working capital.
|
|
/// @dev Prefund this contract with at least the flash fee before calling `runFlashProof`.
|
|
contract DBISEngineXFlashProofBorrower is IERC3156FlashBorrower, Ownable {
|
|
using SafeERC20 for IERC20;
|
|
|
|
bytes32 private constant _RETURN_VALUE = keccak256("ERC3156FlashBorrower.onFlashLoan");
|
|
|
|
IERC3156FlashLender public immutable lender;
|
|
IERC20 public immutable usdc;
|
|
|
|
mapping(bytes32 => bool) public usedProofIds;
|
|
|
|
event EngineXFlashProof(
|
|
bytes32 indexed proofId,
|
|
address indexed initiator,
|
|
address indexed lender,
|
|
address token,
|
|
uint256 amount,
|
|
uint256 fee,
|
|
bytes32 iso20022DocumentHash,
|
|
bytes32 auditEnvelopeHash,
|
|
bytes32 pegProofHash
|
|
);
|
|
|
|
constructor(address lender_, address usdc_, address owner_) Ownable(owner_) {
|
|
require(lender_ != address(0) && usdc_ != address(0), "zero address");
|
|
lender = IERC3156FlashLender(lender_);
|
|
usdc = IERC20(usdc_);
|
|
}
|
|
|
|
function runFlashProof(
|
|
uint256 amount,
|
|
bytes32 proofId,
|
|
bytes32 iso20022DocumentHash,
|
|
bytes32 auditEnvelopeHash,
|
|
bytes32 pegProofHash
|
|
) external onlyOwner returns (bool) {
|
|
require(proofId != bytes32(0), "zero proof");
|
|
require(!usedProofIds[proofId], "proof used");
|
|
require(iso20022DocumentHash != bytes32(0), "zero iso hash");
|
|
require(auditEnvelopeHash != bytes32(0), "zero audit hash");
|
|
require(pegProofHash != bytes32(0), "zero peg hash");
|
|
|
|
bytes memory data = abi.encode(msg.sender, proofId, iso20022DocumentHash, auditEnvelopeHash, pegProofHash);
|
|
return lender.flashLoan(this, address(usdc), amount, data);
|
|
}
|
|
|
|
function onFlashLoan(address initiator, address token, uint256 amount, uint256 fee, bytes calldata data)
|
|
external
|
|
override
|
|
returns (bytes32)
|
|
{
|
|
require(msg.sender == address(lender), "bad lender");
|
|
require(initiator == address(this), "bad initiator");
|
|
require(token == address(usdc), "bad token");
|
|
|
|
(
|
|
address operator,
|
|
bytes32 proofId,
|
|
bytes32 iso20022DocumentHash,
|
|
bytes32 auditEnvelopeHash,
|
|
bytes32 pegProofHash
|
|
) = abi.decode(data, (address, bytes32, bytes32, bytes32, bytes32));
|
|
require(!usedProofIds[proofId], "proof used");
|
|
usedProofIds[proofId] = true;
|
|
|
|
usdc.forceApprove(msg.sender, amount + fee);
|
|
emit EngineXFlashProof(
|
|
proofId, operator, msg.sender, token, amount, fee, iso20022DocumentHash, auditEnvelopeHash, pegProofHash
|
|
);
|
|
return _RETURN_VALUE;
|
|
}
|
|
|
|
function withdraw(address token, address to, uint256 amount) external onlyOwner {
|
|
require(to != address(0), "zero to");
|
|
IERC20(token).safeTransfer(to, amount);
|
|
}
|
|
}
|