Skip to content
Draft
Show file tree
Hide file tree
Changes from 12 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions .github/workflows/check-interface.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
name: Check Interface Consistency

on:
push:
branches: ["main"]
pull_request:
branches: ["main"]

jobs:
check_interface:
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Install Foundry
uses: foundry-rs/foundry-toolchain@v1
with:
version: v1.2.3

- name: Install Dependencies
run: forge install

- name: Install dependencies for interface generation
run: |
sudo apt-get install -y jq
sudo apt-get install -y nodejs

- name: Verify interface
run: |
make interface
git diff --exit-code src/interfaces/IPayments.sol || \
(echo "Interface out of sync. Run 'make interface' locally and commit the changes."; exit 1)

- name: Clean up temporary files
run: rm -rf temp
4 changes: 4 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -75,3 +75,7 @@ transfer-owner: chmod-transfer
get-owner: chmod-get-owner
./tools/get-owner.sh

# Interface generation target
.PHONY: interface
interface:
bash ./tools/generate-interface.sh
24 changes: 1 addition & 23 deletions src/Payments.sol
Original file line number Diff line number Diff line change
Expand Up @@ -11,29 +11,7 @@ import "./RateChangeQueue.sol";
import "@openzeppelin/contracts/utils/Strings.sol";
import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol";
import "./Errors.sol";

interface IValidator {
struct ValidationResult {
// The actual payment amount determined by the validator after validation of a rail during settlement
uint256 modifiedAmount;
// The epoch up to and including which settlement should occur.
uint256 settleUpto;
// A placeholder note for any additional information the validator wants to send to the caller of `settleRail`
string note;
}

function validatePayment(
uint256 railId,
uint256 proposedAmount,
// the epoch up to and including which the rail has already been settled
uint256 fromEpoch,
// the epoch up to and including which validation is requested; payment will be validated for (toEpoch - fromEpoch) epochs
uint256 toEpoch,
uint256 rate
) external returns (ValidationResult memory result);

function railTerminated(uint256 railId, address terminator, uint256 endEpoch) external;
}
import "./interfaces/IValidator.sol";

// @title Payments contract.
contract Payments is Initializable, UUPSUpgradeable, OwnableUpgradeable, ReentrancyGuardUpgradeable {
Expand Down
271 changes: 271 additions & 0 deletions src/interfaces/IPayments.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,271 @@
// SPDX-License-Identifier: MIT
// !! THIS FILE WAS AUTOGENERATED BY abi-to-sol v0.8.0. !!
pragma solidity ^0.8.27;

interface IPayments {
function COMMISSION_MAX_BPS() external view returns (uint256);
function NETWORK_FEE() external view returns (uint256);
function UPGRADE_INTERFACE_VERSION() external view returns (string memory);
function accounts(address, address)
external
view
returns (uint256 funds, uint256 lockupCurrent, uint256 lockupRate, uint256 lockupLastSettledAt);
function createRail(
address token,
address from,
address to,
address validator,
uint256 commissionRateBps,
address serviceFeeRecipient
) external returns (uint256);
function deposit(address token, address to, uint256 amount) external payable;
function depositWithPermit(
address token,
address to,
uint256 amount,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s
) external;
function depositWithPermitAndApproveOperator(
address token,
address to,
uint256 amount,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s,
address operator,
uint256 rateAllowance,
uint256 lockupAllowance,
uint256 maxLockupPeriod
) external;
function depositWithPermitAndIncreaseOperatorApproval(
address token,
address to,
uint256 amount,
uint256 deadline,
uint8 v,
bytes32 r,
bytes32 s,
address operator,
uint256 rateAllowanceIncrease,
uint256 lockupAllowanceIncrease
) external;
function getAccountInfoIfSettled(address token, address owner)
external
view
returns (uint256 fundedUntilEpoch, uint256 currentFunds, uint256 availableFunds, uint256 currentLockupRate);
function getRail(uint256 railId) external view returns (Payments.RailView memory);
function getRailsForPayeeAndToken(address payee, address token)
external
view
returns (Payments.RailInfo[] memory);
function getRailsForPayerAndToken(address payer, address token)
external
view
returns (Payments.RailInfo[] memory);
function getRateChangeQueueSize(uint256 railId) external view returns (uint256);
function hasCollectedFees(address) external view returns (bool);
function increaseOperatorApproval(
address token,
address operator,
uint256 rateAllowanceIncrease,
uint256 lockupAllowanceIncrease
) external;
function initialize() external;
function modifyRailLockup(uint256 railId, uint256 period, uint256 lockupFixed) external;
function modifyRailPayment(uint256 railId, uint256 newRate, uint256 oneTimePayment) external;
function operatorApprovals(address, address, address)
external
view
returns (
bool isApproved,
uint256 rateAllowance,
uint256 lockupAllowance,
uint256 rateUsage,
uint256 lockupUsage,
uint256 maxLockupPeriod
);
function owner() external view returns (address);
function proxiableUUID() external view returns (bytes32);
function renounceOwnership() external;
function setOperatorApproval(
address token,
address operator,
bool approved,
uint256 rateAllowance,
uint256 lockupAllowance,
uint256 maxLockupPeriod
) external;
function settleRail(uint256 railId, uint256 untilEpoch)
external
payable
returns (
uint256 totalSettledAmount,
uint256 totalNetPayeeAmount,
uint256 totalOperatorCommission,
uint256 finalSettledEpoch,
string memory note
);
function settleTerminatedRailWithoutValidation(uint256 railId)
external
returns (
uint256 totalSettledAmount,
uint256 totalNetPayeeAmount,
uint256 totalOperatorCommission,
uint256 finalSettledEpoch,
string memory note
);
function terminateRail(uint256 railId) external;
function transferOwnership(address newOwner) external;
function upgradeToAndCall(address newImplementation, bytes memory data) external payable;
function withdraw(address token, uint256 amount) external;
function withdrawTo(address token, address to, uint256 amount) external;

event AccountLockupSettled(
address indexed token,
address indexed owner,
uint256 lockupCurrent,
uint256 lockupRate,
uint256 lockupLastSettledAt
);
event DepositRecorded(
address indexed token, address indexed from, address indexed to, uint256 amount, bool usedPermit
);
event Initialized(uint64 version);
event OperatorApprovalUpdated(
address indexed token,
address indexed client,
address indexed operator,
bool approved,
uint256 rateAllowance,
uint256 lockupAllowance,
uint256 maxLockupPeriod
);
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
event RailCreated(
uint256 indexed railId,
address indexed payer,
address indexed payee,
address token,
address operator,
address validator,
address serviceFeeRecipient,
uint256 commissionRateBps
);
event RailFinalized(uint256 indexed railId);
event RailLockupModified(
uint256 indexed railId,
uint256 oldLockupPeriod,
uint256 newLockupPeriod,
uint256 oldLockupFixed,
uint256 newLockupFixed
);
event RailOneTimePaymentProcessed(uint256 indexed railId, uint256 netPayeeAmount, uint256 operatorCommission);
event RailRateModified(uint256 indexed railId, uint256 oldRate, uint256 newRate);
event RailSettled(
uint256 indexed railId,
uint256 totalSettledAmount,
uint256 totalNetPayeeAmount,
uint256 operatorCommission,
uint256 settledUpTo
);
event RailTerminated(uint256 indexed railId, address indexed by, uint256 endEpoch);
event Upgraded(address indexed implementation);
event WithdrawRecorded(address indexed token, address indexed from, address indexed to, uint256 amount);

error AddressEmptyCode(address target);
error CannotModifyTerminatedRailBeyondEndEpoch(uint256 railId, uint256 maxSettlementEpoch, uint256 blockNumber);
error CannotSettleFutureEpochs(uint256 railId, uint256 maxAllowedEpoch, uint256 attemptedEpoch);
error CannotSettleTerminatedRailBeforeMaxEpoch(uint256 railId, uint256 requiredBlock, uint256 currentBlock);
error CommissionRateTooHigh(uint256 maxAllowed, uint256 actual);
error CurrentLockupLessThanOldLockup(address token, address from, uint256 oldLockup, uint256 currentLockup);
error ERC1967InvalidImplementation(address implementation);
error ERC1967NonPayable();
error FailedCall();
error InsufficientCurrentLockup(address from, address token, uint256 currentLockup, uint256 lockupReduction);
error InsufficientFundsForOneTimePayment(address token, address from, uint256 required, uint256 actual);
error InsufficientFundsForSettlement(address token, address from, uint256 available, uint256 required);
error InsufficientLockupForSettlement(address token, address from, uint256 available, uint256 required);
error InsufficientNativeTokenForBurn(uint256 required, uint256 sent);
error InsufficientUnlockedFunds(uint256 available, uint256 requested);
error InvalidInitialization();
error InvalidRateChangeQueueState(uint256 nextRateChangeUntilEpoch, uint256 processedEpoch);
error InvalidTerminatedRailModification(
uint256 actualPeriod, uint256 actualLockupFixed, uint256 attemptedPeriod, uint256 attemptedLockupFixed
);
error LockupExceedsFundsInvariant(address token, address account, uint256 lockupCurrent, uint256 fundsCurrent);
error LockupFixedIncreaseNotAllowedDueToInsufficientFunds(
address token, address from, uint256 actualLockupFixed, uint256 attemptedLockupFixed
);
error LockupInconsistencyDuringRailFinalization(
uint256 railId, address token, address from, uint256 expectedLockup, uint256 actualLockup
);
error LockupNotSettledRateChangeNotAllowed(
uint256 railId, address from, bool isSettled, uint256 currentRate, uint256 attemptedRate
);
error LockupPeriodChangeNotAllowedDueToInsufficientFunds(
address token, address from, uint256 actualLockupPeriod, uint256 attemptedLockupPeriod
);
error LockupPeriodExceedsOperatorMaximum(
address token, address operator, uint256 maxAllowedPeriod, uint256 requestedPeriod
);
error LockupRateInconsistent(uint256 railId, address from, uint256 paymentRate, uint256 lockupRate);
error LockupRateLessThanOldRate(uint256 railId, address from, uint256 lockupRate, uint256 oldRate);
error MissingServiceFeeRecipient();
error MustSendExactNativeAmount(uint256 required, uint256 sent);
error NativeTokenNotAccepted(uint256 sent);
error NativeTokenNotSupported();
error NativeTransferFailed(address to, uint256 amount);
error NoProgressInSettlement(uint256 railId, uint256 expectedSettledUpTo, uint256 actualSettledUpTo);
error NotAuthorizedToTerminateRail(uint256 railId, address allowedClient, address allowedOperator, address caller);
error NotInitializing();
error OneTimePaymentExceedsLockup(uint256 railId, uint256 available, uint256 required);
error OnlyRailClientAllowed(address expected, address caller);
error OnlyRailOperatorAllowed(address expected, address caller);
error OnlyRailParticipantAllowed(address expectedFrom, address expectedOperator, address expectedTo, address caller);
error OperatorLockupAllowanceExceeded(uint256 allowed, uint256 attemptedUsage);
error OperatorNotApproved(address from, address operator);
error OperatorRateAllowanceExceeded(uint256 allowed, uint256 attemptedUsage);
error OwnableInvalidOwner(address owner);
error OwnableUnauthorizedAccount(address account);
error PermitRecipientMustBeMsgSender(address expected, address actual);
error RailAlreadyTerminated(uint256 railId);
error RailInactiveOrSettled(uint256 railId);
error RailNotTerminated(uint256 railId);
error RateChangeNotAllowedOnTerminatedRail(uint256 railId);
error RateChangeQueueNotEmpty(uint256 nextUntilEpoch);
error ReentrancyGuardReentrantCall();
error SafeERC20FailedOperation(address token);
error UUPSUnauthorizedCallContext();
error UUPSUnsupportedProxiableUUID(bytes32 slot);
error ValidatorModifiedAmountExceedsMaximum(uint256 railId, uint256 maxAllowed, uint256 attempted);
error ValidatorSettledBeforeSegmentStart(uint256 railId, uint256 allowedStart, uint256 attemptedStart);
error ValidatorSettledBeyondSegmentEnd(uint256 railId, uint256 allowedEnd, uint256 attemptedEnd);
error ZeroAddressNotAllowed(string varName);
}

interface Payments {
struct RailView {
address token;
address from;
address to;
address operator;
address validator;
uint256 paymentRate;
uint256 lockupPeriod;
uint256 lockupFixed;
uint256 settledUpTo;
uint256 endEpoch;
uint256 commissionRateBps;
address serviceFeeRecipient;
}

struct RailInfo {
uint256 railId;
bool isTerminated;
uint256 endEpoch;
}
}
25 changes: 25 additions & 0 deletions src/interfaces/IValidator.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// SPDX-License-Identifier: Apache-2.0 OR MIT
pragma solidity ^0.8.27;

interface IValidator {
struct ValidationResult {
// The actual payment amount determined by the validator after validation of a rail during settlement
uint256 modifiedAmount;
// The epoch up to and including which settlement should occur.
uint256 settleUpto;
// A placeholder note for any additional information the validator wants to send to the caller of `settleRail`
string note;
}

function validatePayment(
uint256 railId,
uint256 proposedAmount,
// the epoch up to and including which the rail has already been settled
uint256 fromEpoch,
// the epoch up to and including which validation is requested; payment will be validated for (toEpoch - fromEpoch) epochs
uint256 toEpoch,
uint256 rate
) external returns (ValidationResult memory result);

function railTerminated(uint256 railId, address terminator, uint256 endEpoch) external;
}
Loading