Skip to content

Commit

Permalink
feat: extract Originator into a base abstract
Browse files Browse the repository at this point in the history
  • Loading branch information
dangerousfood committed Oct 17, 2023
1 parent 4384135 commit ed66465
Show file tree
Hide file tree
Showing 12 changed files with 288 additions and 439 deletions.
1 change: 0 additions & 1 deletion src/Custodian.sol
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ import {ContractOffererInterface} from "seaport-types/src/interfaces/ContractOff
import {ConduitHelper} from "starport-core/ConduitHelper.sol";
import {TokenReceiverInterface} from "starport-core/interfaces/TokenReceiverInterface.sol";
import {FixedPointMathLib} from "solady/src/utils/FixedPointMathLib.sol";
import {Originator} from "starport-core/originators/Originator.sol";
import {SettlementHook} from "starport-core/hooks/SettlementHook.sol";
import {SettlementHandler} from "starport-core/handlers/SettlementHandler.sol";
import {Pricing} from "starport-core/pricing/Pricing.sol";
Expand Down
1 change: 0 additions & 1 deletion src/handlers/DutchAuctionHandler.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import {
OrderParameters
} from "seaport-types/src/lib/ConsiderationStructs.sol";

import {Originator} from "starport-core/originators/Originator.sol";
import {Pricing} from "starport-core/pricing/Pricing.sol";
import {AmountDeriver} from "seaport-core/src/lib/AmountDeriver.sol";
import {FixedPointMathLib} from "solady/src/utils/FixedPointMathLib.sol";
Expand Down
198 changes: 2 additions & 196 deletions src/originators/Originator.sol
Original file line number Diff line number Diff line change
Expand Up @@ -22,31 +22,17 @@ pragma solidity =0.8.17;

import {LoanManager} from "starport-core/LoanManager.sol";

import {ItemType, ReceivedItem, SpentItem} from "seaport-types/src/lib/ConsiderationStructs.sol";
import {SpentItem} from "seaport-types/src/lib/ConsiderationStructs.sol";
import {ConduitTransfer, ConduitItemType} from "seaport-types/src/conduit/lib/ConduitStructs.sol";
import {ConduitControllerInterface} from "seaport-types/src/interfaces/ConduitControllerInterface.sol";
import {ConduitInterface} from "seaport-types/src/interfaces/ConduitInterface.sol";

import {ECDSA} from "solady/src/utils/ECDSA.sol";
import {SignatureCheckerLib} from "solady/src/utils/SignatureCheckerLib.sol";
import {Ownable} from "solady/src/auth/Ownable.sol";

// Validator abstract contract that lays out the necessary structure and functions for the validator
abstract contract Originator is Ownable {
enum State {
INITIALIZED,
CLOSED
}

struct Response {
LoanManager.Terms terms;
address issuer;
}

event StrategistTransferred(address newStrategist);

mapping(bytes32 => bool) public usedHashes;

struct Request {
address custodian;
address receiver;
Expand All @@ -56,79 +42,9 @@ abstract contract Originator is Ownable {
bytes approval;
}

struct Details {
address custodian;
address conduit;
address issuer;
uint256 deadline;
Offer offer;
}

struct Offer {
bytes32 salt; //can be bytes32(0) if so do not invalidate the hash
LoanManager.Terms terms;
SpentItem[] collateral;
SpentItem[] debt;
}

event Origination(uint256 indexed loanId, address indexed issuer, bytes nlrDetails);

event CounterUpdated();

event HashInvalidated(bytes32 hash);

modifier onlyLoanManager() {
if (msg.sender != address(LM)) {
revert NotLoanManager();
}
_;
}

error NotLoanManager();
error NotAuthorized();
error InvalidDebt();
error InvalidDebtLength();
error InvalidDebtAmount();
error InvalidCustodian();
error InvalidCollateral();
error InvalidDeadline();
error InvalidOffer();
error InvalidSigner();
error ConduitTransferError();

LoanManager public immutable LM;

// Define the EIP712 domain and typehash constants for generating signatures
bytes32 constant EIP_DOMAIN = keccak256("EIP712Domain(string version,uint256 chainId,address verifyingContract)");
bytes32 public constant ORIGINATOR_DETAILS_TYPEHASH = keccak256("Origination(uint256 nonce,bytes32 hash)");
bytes32 constant VERSION = keccak256("0");

bytes32 internal immutable _DOMAIN_SEPARATOR;

// Strategist address and fee
address public strategist;
uint256 public strategistFee;
uint256 private _counter;

constructor(LoanManager LM_, address strategist_, uint256 fee_, address owner) {
_initializeOwner(owner);
strategist = strategist_;
strategistFee = fee_;
LM = LM_;
_DOMAIN_SEPARATOR = keccak256(
abi.encode(
EIP_DOMAIN,
VERSION, //version
block.chainid,
address(this)
)
);
}

function setStrategist(address newStrategist) external onlyOwner {
strategist = newStrategist;
emit StrategistTransferred(newStrategist);
}
function execute(Request calldata params) external virtual returns (Response memory response);

function _packageTransfers(SpentItem[] memory loan, address borrower, address issuer)
internal
Expand Down Expand Up @@ -162,114 +78,4 @@ abstract contract Originator is Ownable {
}
}
}

function terms(bytes calldata details) public view virtual returns (LoanManager.Terms memory) {
return abi.decode(details, (Details)).offer.terms;
}

function execute(Request calldata params) external virtual returns (Response memory response);

function _buildResponse(Request calldata params, Details memory details)
internal
virtual
returns (Response memory response)
{
response = Response({terms: details.offer.terms, issuer: details.issuer});
}

// Encode the data with the account's nonce for generating a signature
function encodeWithAccountCounter(bytes32 contextHash) public view virtual returns (bytes memory) {
bytes32 hash = keccak256(abi.encode(ORIGINATOR_DETAILS_TYPEHASH, _counter, contextHash));

return abi.encodePacked(bytes1(0x19), bytes1(0x01), _DOMAIN_SEPARATOR, hash);
}

function getStrategistData() public view virtual returns (address, uint256) {
return (strategist, strategistFee);
}

// Get the nonce of an account
function getCounter() public view virtual returns (uint256) {
return _counter;
}

function incrementCounter() external {
if (msg.sender != strategist || msg.sender != owner()) {
revert NotAuthorized();
}
_counter += uint256(blockhash(block.number - 1) << 0x80);
emit CounterUpdated();
}

// Function to generate the domain separator for signatures
function domainSeparator() public view virtual returns (bytes32) {
return _DOMAIN_SEPARATOR;
}

function _validateAsk(Request calldata request, Details memory details) internal virtual {
if (keccak256(abi.encode(request.collateral)) != keccak256(abi.encode(details.offer.collateral))) {
revert InvalidCollateral();
}

//loop through collateral and check if the collateral is the same

for (uint256 i = 0; i < request.collateral.length;) {
if (
request.debt[i].itemType != details.offer.debt[i].itemType
|| request.debt[i].token != details.offer.debt[i].token
|| request.debt[i].identifier != details.offer.debt[i].identifier
) {
revert InvalidDebt();
}

if (
request.debt[i].amount > details.offer.debt[i].amount || request.debt[i].amount == 0
|| details.offer.debt[i].amount == 0
) {
revert InvalidDebtAmount();
}
unchecked {
i++;
}
}
}

function _validateOffer(Request calldata request, Details memory details) internal virtual {
bytes32 contextHash = keccak256(request.details);
_validateSignature(keccak256(encodeWithAccountCounter(keccak256(request.details))), request.approval);
if (request.custodian != details.custodian) {
revert InvalidCustodian();
}
if (request.debt.length != details.offer.debt.length) {
revert InvalidDebtLength();
}
_validateAsk(request, details);

if (details.offer.salt != bytes32(0)) {
if (!usedHashes[contextHash]) {
usedHashes[contextHash] = true;
emit HashInvalidated(contextHash);
} else {
revert InvalidOffer();
}
}
if (block.timestamp > details.deadline) {
revert InvalidDeadline();
}
}

function _execute(Request calldata request, Details memory details) internal virtual {
if (
ConduitInterface(details.conduit).execute(_packageTransfers(request.debt, request.receiver, details.issuer))
!= ConduitInterface.execute.selector
) {
revert ConduitTransferError();
}
}

function _validateSignature(bytes32 hash, bytes memory signature) internal view virtual {
if (!SignatureCheckerLib.isValidSignatureNow(strategist, hash, signature)) {
revert InvalidSigner();
}
}
}
141 changes: 0 additions & 141 deletions src/originators/PoolOriginator.sol

This file was deleted.

Loading

0 comments on commit ed66465

Please sign in to comment.