diff --git a/scripts/verify.sh b/scripts/verify.sh new file mode 100644 index 00000000..4f773192 --- /dev/null +++ b/scripts/verify.sh @@ -0,0 +1,30 @@ +#!/usr/bin/env bash +# takes in a deployment file and the chain id verifies on etherscan +# needs to have ETHERSCAN_API_KEY set in the environment +set -e +INPUT_FILE=$1 +ARG_FILE="$(dirname $INPUT_FILE)/arguments.json" +CHAIN_ID=$(jq -r '.chain' < $INPUT_FILE) +COMPILER_VERSION="0.8.17" +for row in $(jq -c '.transactions[]' < ${INPUT_FILE}); do + _jq() { + echo ${row} | jq -r ${1} + } + + if [[ $(_jq '.transactionType') == "CREATE" ]]; then + + args=$(_jq '.arguments') + CONSTRUCTOR_ARGS_PATH="" + if [[ ${args} != "null" ]]; then + echo ${args} > "${ARG_FILE}" + CONSTRUCTOR_ARGS_PATH=--constructor-args-path=${ARG_FILE} + fi + if ! forge verify-contract "$(_jq '.contractAddress')" "$(_jq '.contractName')" -e ${ETHERSCAN_API_KEY} --chain ${CHAIN_ID} --compiler-version ${COMPILER_VERSION} ${CONSTRUCTOR_ARGS_PATH} + then + echo "failed to verify $(_jq '.contractName')" + continue + fi + + fi +done +rm -f ${ARG_FILE} \ No newline at end of file diff --git a/src/lib/StarportLib.sol b/src/lib/StarportLib.sol index 564b639d..c48fad84 100644 --- a/src/lib/StarportLib.sol +++ b/src/lib/StarportLib.sol @@ -87,7 +87,7 @@ library StarportLib { /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ function calculateSimpleInterest(uint256 delta_t, uint256 amount, uint256 rate, uint256 decimals) - public + internal pure returns (uint256) { diff --git a/src/lib/StarportValidator.sol b/src/lib/StarportValidator.sol new file mode 100644 index 00000000..51936e3a --- /dev/null +++ b/src/lib/StarportValidator.sol @@ -0,0 +1,120 @@ +pragma solidity ^0.8.0; + +import {Validation} from "./Validation.sol"; +import {Starport} from "../Starport.sol"; +import {Custodian} from "../Custodian.sol"; +import {Pricing} from "../pricing/Pricing.sol"; +import {Status} from "../status/Status.sol"; +import {Settlement} from "../settlement/Settlement.sol"; +import {SignatureCheckerLib} from "solady/src/utils/SignatureCheckerLib.sol"; +import {CaveatEnforcer} from "../enforcers/CaveatEnforcer.sol"; +import {AdditionalTransfer} from "./StarportLib.sol"; + +contract StarportValidator { + struct ValidationError { + ErrorSet[] errors; + } + + struct ErrorSet { + string msg; + CODES codes; + } + + //is the sig valid + //are the params valid + //are these module contracts we approve + //is there time remaining + //has the salt been filled + //is the nonce correct + enum CODES { + INVALID_MODULE, + EMPTY_CAVEAT, + VALIDATION, + CAVEAT_EXPIRED, + INVALID_CAVEAT, + INVALID_CAVEAT_LENGTH, + INVALID_SALT, + INVALID_HASH, + INVALID_SIGNATURE + } + + ValidationError private validation; + + function validateOriginate( + address[3] memory validModules, //pricing,status,settlement + Starport starport, + Custodian custodian, + address fulfiller, + AdditionalTransfer[] calldata additionalTransfers, + CaveatEnforcer.SignedCaveats calldata borrowerCaveat, + CaveatEnforcer.SignedCaveats calldata lenderCaveat, + Starport.Loan memory loan + ) public returns (bytes memory output) { + if (fulfiller != loan.borrower) { + if (keccak256(abi.encode(borrowerCaveat)) == _emptyCaveatHash()) { + validation.errors.push(ErrorSet({msg: "Borrower", codes: CODES.EMPTY_CAVEAT})); + } else if (borrowerCaveat.deadline > block.timestamp) { + validation.errors.push(ErrorSet({msg: "Borrower", codes: CODES.CAVEAT_EXPIRED})); + } + + bytes32 caveatHash = starport.hashCaveatWithSaltAndNonce( + fulfiller, + borrowerCaveat.singleUse, + borrowerCaveat.salt, + borrowerCaveat.deadline, + borrowerCaveat.caveats + ); + if (starport.invalidSalts(fulfiller, caveatHash)) { + validation.errors.push(ErrorSet({msg: "Borrower", codes: CODES.INVALID_SALT})); + } + if (!SignatureCheckerLib.isValidSignatureNowCalldata(fulfiller, caveatHash, borrowerCaveat.signature)) { + validation.errors.push(ErrorSet({msg: "Borrower", codes: CODES.INVALID_SIGNATURE})); + } + } + if (fulfiller != loan.issuer) { + if (keccak256(abi.encode(lenderCaveat)) == _emptyCaveatHash()) { + validation.errors.push(ErrorSet({msg: "Lender", codes: CODES.EMPTY_CAVEAT})); + } else if (lenderCaveat.deadline > block.timestamp) { + validation.errors.push(ErrorSet({msg: "Lender", codes: CODES.CAVEAT_EXPIRED})); + } + + bytes32 caveatHash = starport.hashCaveatWithSaltAndNonce( + fulfiller, lenderCaveat.singleUse, lenderCaveat.salt, lenderCaveat.deadline, lenderCaveat.caveats + ); + if (starport.invalidSalts(fulfiller, caveatHash)) { + validation.errors.push(ErrorSet({msg: "Lender", codes: CODES.INVALID_SALT})); + } + if (!SignatureCheckerLib.isValidSignatureNowCalldata(fulfiller, caveatHash, lenderCaveat.signature)) { + validation.errors.push(ErrorSet({msg: "Lender", codes: CODES.INVALID_SIGNATURE})); + } + } + if (validModules[0] != loan.terms.pricing) { + validation.errors.push(ErrorSet({msg: "Pricing", codes: CODES.INVALID_MODULE})); + } + if (validModules[1] != loan.terms.status) { + validation.errors.push(ErrorSet({msg: "Status", codes: CODES.INVALID_MODULE})); + } + if (validModules[2] != loan.terms.settlement) { + validation.errors.push(ErrorSet({msg: "Settlement", codes: CODES.INVALID_MODULE})); + } + if (loan.custodian != address(custodian)) { + validation.errors.push(ErrorSet({msg: "Custodian", codes: CODES.INVALID_MODULE})); + } + if (Pricing(loan.terms.pricing).validate(loan) != Validation.validate.selector) { + validation.errors.push(ErrorSet({msg: "Pricing", codes: CODES.VALIDATION})); + } + if (Status(loan.terms.status).validate(loan) != Validation.validate.selector) { + validation.errors.push(ErrorSet({msg: "Status", codes: CODES.VALIDATION})); + } + if (Settlement(loan.terms.settlement).validate(loan) != Validation.validate.selector) { + validation.errors.push(ErrorSet({msg: "Settlement", codes: CODES.VALIDATION})); + } + + return abi.encode(validation); + } + + function _emptyCaveatHash() internal returns (bytes32) { + CaveatEnforcer.SignedCaveats memory emptyCaveat; + return keccak256(abi.encode(emptyCaveat)); + } +} diff --git a/src/scripts/Deploy.sol b/src/scripts/Deploy.sol new file mode 100644 index 00000000..26d31d39 --- /dev/null +++ b/src/scripts/Deploy.sol @@ -0,0 +1,21 @@ +pragma solidity ^0.8.0; + +import "forge-std/Script.sol"; + +import {Starport, Stargate} from "starport-core/Starport.sol"; +import {SimpleInterestPricing} from "starport-core/pricing/SimpleInterestPricing.sol"; +import {FixedTermStatus} from "starport-core/status/FixedTermStatus.sol"; +import {FixedTermDutchAuctionSettlement} from "starport-core/settlement/FixedTermDutchAuctionSettlement.sol"; + +contract Deploy is Script { + address public constant seaport = address(0x00000000000000ADc04C56Bf30aC9d3c0aAF14dC); + + function run() public { + vm.startBroadcast(); + Starport SP = new Starport(seaport, Stargate(address(0))); + new FixedTermDutchAuctionSettlement(SP); + new FixedTermStatus(); + new SimpleInterestPricing(SP); + vm.stopBroadcast(); + } +} diff --git a/test/StarportTest.sol b/test/StarportTest.sol index 9c94750a..fdd80811 100644 --- a/test/StarportTest.sol +++ b/test/StarportTest.sol @@ -558,9 +558,7 @@ contract StarportTest is BaseOrderTest, Stargate { pure returns (ConsiderationItem[] memory) { - ConsiderationItem[] memory considerationItems = new ConsiderationItem[]( - _receivedItems.length - ); + ConsiderationItem[] memory considerationItems = new ConsiderationItem[](_receivedItems.length); for (uint256 i = 0; i < _receivedItems.length; ++i) { considerationItems[i] = ConsiderationItem( _receivedItems[i].itemType, diff --git a/test/integration-testing/TestNewLoan.sol b/test/integration-testing/TestNewLoan.sol index 590a0aa7..c77857ff 100644 --- a/test/integration-testing/TestNewLoan.sol +++ b/test/integration-testing/TestNewLoan.sol @@ -386,9 +386,7 @@ contract TestNewLoan is StarportTest { (ReceivedItem[] memory settlementConsideration, address authorized) = Settlement(activeLoan.terms.settlement).getSettlementConsideration(activeLoan); settlementConsideration = StarportLib.removeZeroAmountItems(settlementConsideration); - ConsiderationItem[] memory consider = new ConsiderationItem[]( - settlementConsideration.length - ); + ConsiderationItem[] memory consider = new ConsiderationItem[](settlementConsideration.length); uint256 i = 0; for (; i < settlementConsideration.length;) { consider[i].token = settlementConsideration[i].token; @@ -401,9 +399,7 @@ contract TestNewLoan is StarportTest { ++i; } } - OfferItem[] memory repayOffering = new OfferItem[]( - activeLoan.collateral.length - ); + OfferItem[] memory repayOffering = new OfferItem[](activeLoan.collateral.length); i = 0; for (; i < activeLoan.collateral.length;) { repayOffering[i] = OfferItem({