Appearance
PayPledge Smart Contract
Overview
The PayPledge smart contract is the core component of the paypledge platform, deployed on a private EVM network. It manages a collateral-backed payment pledge from a buyer (payer) to a seller (payee), using Trade Tokens (ERC-3643) as collateral, represented as ERC-1155 tokens while under lock. The contract oversees the payment pledge lifecycle, including collateral deposit, condition fulfillment, seller acceptance, and settlement (repayment or default), with a refutation and dispute resolution mechanism.
This contract interacts with:
- Buyer (payer), who initializes and discharges the pledge.
- Seller (payee), who accepts the pledge and delivers goods.
- Underwriters, who deposit collateral via the
CollateralManagercontract. - Dispute Resolve, who resolve disputes.
- Payment Processor, who exchanges ERC-1155 tokens for early fiat financing.
CollateralManagercontract, which transfers collateral.- Trade Token (ERC-3643), used as collateral.
Key Functionalities
1. Pledge Lifecycle Management
- Manages the lifecycle:
DRAFTING,INITIATED,ACCEPTED,CONTINGENT,EFFECTIVE,DISCHARGING,DISCHARGED. - Tracks discharge status:
OPEN,DISCHARGE_INITIATED,DISCHARGE_REFUTED,DISCHARGED. - Transitions occur based on actions like initiation, acceptance, condition fulfillment, and discharge.
2. Collateral Management
- Receives Trade Tokens (ERC-3643) as collateral from the
CollateralManagercontract via thedepositCollateralfunction (in addition to the standarddepositfunction). - Only the CollateralManager contract can call
depositCollateral, ensuring that collateral is only deposited as a result of a validated underwriting process. - Mints ERC-1155 tokens (token proxy) to represent the collateral, held by the seller or Payment Processor.
- Transfers and burns of ERC-1155 tokens during discharge (repayment or default) using
withdraw. - CollateralManager-driven flows ensure that only selected underwriter offers (CUOfs) result in collateral being locked in the PayPledge contract.
- The contract stores the address of the CollateralManager and restricts certain functions to only be callable by this address.
3. Conditions and Refutations
- Supports conditions (e.g., trade conditions for goods delivery) with statuses:
NULL,UNFULFILLED,FULFILLMENT_INITIATED,FULFILLMENT_REFUTED,FULFILLED. - Allows refutations within a
refutationWindow(e.g., 1 day) for condition fulfillment and discharge, resolved by the Dispute Resolver.
4. Seller Acceptance and Delivery
- Enables the seller to accept the pledge (
accept) and fulfill delivery conditions (fulfillCondition), moving the status toEFFECTIVE.
5. Compatability With Token Exchange for Early Financing
- Allows the beneficiary to use their erc-1155 tokens in external trade contracts like the Token Exchange.
6. Discharge (Repayment or Default)
- Repayment: Buyer initiates discharge (
initiateDischarge), returning collateral (ERC-1155 tokens) to the underwriter after the refutation window. - Default: Payment Processor initiates
initiateDefaultDischarge, claiming the collateral after the due date (60 days). - Handles refutations and dispute resolution with the help of the Dispute Resolver.
7. Change Requests
- Allows the seller to request changes to the collateral value or due date (±5% range for collateral value).
Roles
- Buyer (
payer):- Initializes the pledge and initiates discharge on repayment.
- Address: Immutable, set during deployment.
- Seller (
payee):- Accepts the pledge, fulfills delivery conditions, and initiates token exchange.
- Underwriter:
- Provides collateral via the
CollateralManagercontract.
- Provides collateral via the
- DisputeResolver:
- Resolves disputes.
- Address: Set during initiation.
Events
StatusUpdated(PledgeStatus newStatus):- Emitted when the pledge status changes.
DischargeStatusUpdated(DischargeStatus newValue):- Emitted when the discharge status changes.
PaymentValueUpdated(uint256 oldValue, uint256 newValue):- Emitted when the collateral value is updated.
DueDateUpdated(uint256 oldValue, uint256 newValue):- Emitted when the due date is updated.
TokensDeposited(address indexed depositor, address indexed token, uint256 value, uint256 tokenId):- Emitted when collateral is deposited.
TokensWithdrawn(address indexed from, address indexed token, uint256 value, address indexed to):- Emitted when collateral is withdrawn.
ConditionAdded(uint256 conditionId, address indexed fulfiller):- Emitted when a condition is added.
ConditionFulfillmentInitiated(address fulfiller, uint256 conditionId):- Emitted when condition fulfillment is initiated.
ConditionFulfilled(uint256 conditionId):- Emitted when a condition is fulfilled.
ConditionFulfillmentRefuted(address refuter, uint256 conditionId):- Emitted when a condition fulfillment is refuted.
ConditionFulfillmentCancelled(address sender, uint256 conditionId):- Emitted when a condition fulfillment is cancelled.
DischargeInitiated():- Emitted when discharge (repayment or default) is initiated.
DischargeRefuted(address refuter):- Emitted when discharge is refuted.
DischargeCancelled():- Emitted when discharge is cancelled.
DischargeCompleted():- Emitted when discharge is completed.
CollateralDeposited(address indexed underwriter, address indexed token, uint256 value, address indexed to):- Emitted when the CollateralManager deposits collateral on behalf of an underwriter via
depositCollateral.
- Emitted when the CollateralManager deposits collateral on behalf of an underwriter via
underwriterPermissionUpdates(address underwriter, bool permission):- Emitted when underwriter permissions are updated by the paypledge owner.
Contract Structure
State Variables
string public name: Contract name.uint256 public decimals: Token decimals.string public referenceId: An arbitrary reference ID, set by the initiator for identifying the pay pledge.address public immutable PAYER: The buyer address (immutable).address public payee: The seller address.address public disputeResolver: The Dispute Resolver's address.address public collateralToken: The Trade Token (ERC-3643) address.address public collateralManager: The CollateralManager contract address.address public collateralDepositor: The account address that deposited the collateral for this pay pledge.uint256 public collateralDeposited: The amount of collateral tokens deposited by collateral depositor.uint256 public paymentValue: The value of collateral used in the pay pledge.uint256 public pledgeDate: The timestamp when the pledge was made.uint256 public dueDate: The due date for repayment (e.g., 60 days).uint256 public refutationWindow: The time window (in seconds) for refutations.mapping(address => bool) public whitelistedUnderwriters: The addresses whitelisted to participate in the underwriting for this pay pledge.enum PledgeStatus { DRAFTING, INITIATED, ACCEPTED, CONTINGENT, EFFECTIVE, DISCHARGING, DISCHARGED }: Pledge lifecycle status.enum DischargeStatus { OPEN, DISCHARGE_INITIATED, DEFAULT_DISCHARGE_INITIATED, DISCHARGE_REFUTED, DISCHARGED }: Discharge process status.enum ConditionStatus { NULL, UNFULFILLED, FULFILLMENT_INITIATED, FULFILLMENT_REFUTED, FULFILLED }: Condition status.enum ChangeTypes { COLLATERAL_VALUE, DUE_DATE }: Change types.enum ConditionActions { NULL, DEPOSIT, COLLATERAL_DEPOSIT, ACCEPT, FULFILL_CONDITION, DISCHARGE }: Condition actions.enum ConditionRequiredFields { TRADE_TOKEN_ADDRESS, TRADE_TOKEN_VALUE }: Condition required fields.enum ConditionFulfillmentActions { SET_VALUE }: Condition fulfillment actions.enum ConditionFulfillmentFields { STATUS, DISCHARGE_STATUS, TRANSFER_FROM, TRANSFER_TO, TRANSFER_VALUE, TRANSFER_TOKEN_ID }: Condition fulfillment fields.PledgeStatus public status: Current pledge status.DischargeStatus public dischargeStatus: Current discharge status.struct Condition { enum ConditionActions action; struct FieldRequirement[] requiredFields; address fulfiller; enum ConditionStatus status; enum ConditionFulfillmentActions fulfillmentAction; struct FieldUpdate[] fulfillmentFields; uint256 fulfillmentRequestTimestamp; }: Structure to store condition details.struct NewCondition { uint256 conditionId; enum ConditionActions triggeringAction; enum ConditionRequiredFields[] requiredFields; bytes[] requiredValues; address fulfiller; enum ConditionFulfillmentActions fulfillmentAction; enum ConditionFulfillmentFields[] fulfillmentFields; bytes[] fulfillmentValues; }: Structure for new conditions.struct FieldRequirement { enum ConditionRequiredFields field; bytes value; }: Structure for field requirements.struct FieldUpdate { enum ConditionFulfillmentFields field; bytes value; }: Structure for field updates.mapping(uint256 => Condition) public conditions: Mapping of condition IDs to conditions.uint256[] public conditionIds: Array of condition IDs.address[] public dischargeAccounts: Accounts to be drained on discharge.uint256[] public dischargeValues: Values to be drained on discharge.address public dischargeToken: Token to be drained on discharge.
Functions
Constructor
constructor(address _initialOwner, address _payer, string memory _erc1155Uri):- Initializes the contract with the owner, payer, and ERC-1155 URI.
- Sets the contract status to "DRAFTING" and discharge status to "OPEN".
Admin Functions
whitelistUnderwriter(address underwriter, bool permission):- Allows the contract owner to add or remove underwriters from the whitelist.
- Only whitelisted underwriters can participate in the underwriting process.
- Emits
underwriterPermissionUpdates.
Buyer Functions
initiate(string memory _referenceId, address _payee, address _collateralToken, uint256 _paymentValue, uint256 _pledgeDate, uint256 _dueDate, uint256 _refutationWindow, address _disputeResolver, NewCondition[] memory _newConditions):- Initiates the pledge with the specified details and conditions.
- Only callable by the contract deployer.
- Emits
StatusUpdated.
addCondition(uint256 _conditionId, ConditionActions _triggeringAction, ConditionRequiredFields[] memory _requiredFields, bytes[] memory _requiredValues, address _fulfiller, ConditionFulfillmentActions _fulfillmentAction, ConditionFulfillmentFields[] memory _fulfillmentFields, bytes[] memory _fulfillmentValues):- Adds a new condition to the pledge.
- Only callable by the paypledge owner(payer).
- Emits
ConditionAdded.
initiateDischarge(address[] calldata accounts):- Initiates discharge on repayment, specifying accounts to receive collateral.
- Only callable by the payer.
- Emits
DischargeInitiated,StatusUpdated.
completeDischarge():- Completes discharge after the refutation window, transferring collateral back to the underwriter.
- Callable by the payer or Dispute Resolver (if refuted).
- Emits
DischargeCompleted,StatusUpdated.
Seller Functions
accept():- Accepts the pledge, moving status to
ACCEPTED. - Only callable by the payee.
- Emits
StatusUpdated.
- Accepts the pledge, moving status to
fulfillCondition(uint256 conditionId):- Fulfills a condition (e.g., delivery), moving status to
EFFECTIVEif applicable. - Only callable by the condition’s fulfiller (e.g., payee).
- Emits
ConditionFulfilled,StatusUpdated.
- Fulfills a condition (e.g., delivery), moving status to
initiateConditionFulfillment(uint256 conditionId):- Initiates condition fulfillment, starting the refutation window.
- Only callable by the condition’s fulfiller.
- Emits
ConditionFulfillmentInitiated.
completeConditionFulfillment(uint256 conditionId):- Completes condition fulfillment after the refutation window.
- Callable by the fulfiller or Dispute Resolver (if refuted).
- Emits
ConditionFulfilled,StatusUpdated.
requestChange(ChangeTypes _changeType, bytes memory newValue):- Requests a change to the collateral value or due date.
- Only callable by the payee.
- Emits
PaymentValueUpdatedorDueDateUpdated.
Collateral Beneficiary Functions(seller/payment processor)
initiateDefaultDischarge(address[] calldata accounts):- Initiates discharge on default, claiming the collateral after the due date.
- Only callable by accounts with a collateral balance(e.g.: Payment Processor).
- Emits
DischargeInitiated,StatusUpdated.
completeDefaultDischarge():- Completes the default discharge process after the refutation window has passed.
- Callable by collateral owner or dispute resolver.
- Emits
DischargeCompleted,StatusUpdated.
Refutation Functions
refuteConditionFulfillment(uint256 conditionId):- Refutes a condition fulfillment within the refutation window.
- Callable by the payer or payee.
- Emits
ConditionFulfillmentRefuted.
cancelConditionFulfillment(uint256 conditionId):- Cancels a condition fulfillment if refuted.
- Callable by the Dispute Resolver or fulfiller.
- Emits
ConditionFulfillmentCancelled.
refuteDischarge():- Refutes a discharge within the refutation window.
- Callable by collateral holders (e.g., Seller or Payment Processor).
- Emits
DischargeRefuted.
cancelDischarge():- Cancels a discharge if refuted.
- Only callable by the Dispute Resolver.
- Emits
DischargeCancelled,StatusUpdated.
Collateral Functions
depositCollateral(uint256 _value):- Allows whitelisted underwriters to deposit collateral tokens that back the pledge.
- Only callable by whitelisted underwriters.
- Emits
TokensDeposited.
deposit(address _token, uint256 _value, address _to):- Deposits Trade Tokens, minting ERC-1155 tokens.
- Fulfills deposit conditions if applicable.
- Emits
TokensDeposited,StatusUpdated.
withdraw(address _token, uint256 _value, address _to):- Withdraws Trade Tokens, burning ERC-1155 tokens.
- Restricted until after the due date or
DISCHARGEDstatus. - Emits
TokensWithdrawn.
ERC-1155 Functions
safeTransferFrom(address from, address to, uint256 id, uint256 value, bytes data):- Safely transfers ERC-1155 tokens with custom collateral restrictions.
- Only internal transfers are used in the current implementation.
safeBatchTransferFrom(address from, address to, uint256[] ids, uint256[] values, bytes data):- Safely transfers a batch of ERC-1155 tokens with custom collateral restrictions.
- Only internal transfers are used in the current implementation.
onERC1155Received(address, address, uint256, uint256, bytes) external pure returns (bytes4):- Handles the receipt of a single ERC-1155 token transfer.
- Required for ERC1155 compliance.
onERC1155BatchReceived(address, address, uint256[], uint256[], bytes) external pure returns (bytes4):- Handles the receipt of a batch of ERC-1155 token transfers.
- Required for ERC1155 compliance.
Internal Functions
_verifyCondition(uint256 _conditionId, address _token, uint256 _value) internal view returns (bool):- Verifies if a condition is met based on the provided token and value.
_fulfillCondition(uint256 _conditionId) internal:- Internal function to fulfill a condition and execute its associated actions.
_isCompatibleERC20(address token) internal returns (bool, string):- Checks if the specified address is a valid ERC20 token.
_deleteCondition(uint256 _conditionId) internal:- Deletes the specified condition and removes it from the conditionIds array.
_isDischargeAccount(address _account) internal view returns (bool):- Checks if the specified address is a discharge account.
View Functions
getStatus() external view returns (PledgeStatus):- Returns the current pledge status.
getConditionCount() public view returns (uint256):- Returns the total number of conditions.
getAllConditionIds() public view returns (uint256[] memory):- Returns an array of all condition IDs.
Errors
PayPledgeInvalidAddress(address receivedAddress):- Thrown when an invalid address is received.
PayPledgeConditionAlreadyExists(uint256 conditionId):- Thrown when a condition with the specified ID already exists.
PayPledgeInvalidConditionStatus(enum ConditionStatus conditionStatus):- Thrown when the status of a condition is invalid.
PayPledgeTransferFailed(address token, address to, uint256 value):- Thrown when an ERC-20 token transfer fails.
PayPledgeInvalidStatus(enum PledgeStatus status):- Thrown when the deposit state is invalid.
PayPledgeUnauthorizedCaller(address sender):- Thrown when an unauthorized caller attempts to interact with the contract.
PayPledgeInvalidConditionId(uint256 conditionId):- Thrown when an invalid condition ID is provided.
PayPledgeInvalidDischargeStatus(enum DischargeStatus dischargeStatus):- Thrown when the discharge status is invalid.
PayPledgeUnauthorizedCollateralWithdrawal(uint256 dueDateTill, enum PledgeStatus status):- Thrown when an unauthorized attempt is made to withdraw collateral.
PayPledgeDueDateNotPassed(uint256 currentTime, uint256 dueDate):- Thrown when an action is attempted before the due date has passed.
PayPledgeActiveRefutationWindow(uint256 currentTime, uint256 refutationWindowTill):- Thrown when a refutation window is still active for a pay pledge.
PayPledgeInvalidDischargeTimestamp(uint256 currentTime, uint256 dueDate):- Thrown when a default discharge request is sent before due date.
PayPledgeUnauthorizedResolver(address sender, address disputeResolver):- Thrown when an unauthorized resolver attempts to resolve a dispute.
PayPledgeUnauthorizedCollateralTransfer():- Thrown when an unauthorized attempt is made to transfer collateral.
PayPledgeInvalidValueChange(uint256 current, uint256 newValue, uint256 lowerBound, uint256 upperBound):- Thrown when a value change is outside the allowed range.
ERC1155MissingApprovalForAll(address operator, address owner):- Thrown when there's a failure with the operator's approval.
PayPledgeInvalidData():- Thrown when invalid data is provided.
Security Considerations
- Access Control:
- Role-based restrictions ensure only authorized parties (payer, payee, Payment Processor) can call specific functions.
- Collateral Safety:
- ERC-1155 tokens are minted and transferred securely, ensuring collateral integrity.
- Trade Tokens are only released after proper discharge or due date expiration.
- Reentrancy Protection:
- Functions that modify state (e.g.,
deposit,withdraw,initiateDischarge) use reentrancy guards to prevent reentrancy attacks.
- Functions that modify state (e.g.,
- Refutation Window:
- The
refutationWindowensures parties have time to dispute actions, with the Dispute Resolver as the final arbiter.
- The
Dependencies
- OpenZeppelin Contracts:
Ownable: For access control (Dispute Resolver).ReentrancyGuard: For reentrancy protection.ERC1155: For managing token proxies (collateral representation).IERC20: For interacting with Trade Tokens (ERC-3643).
- External Contracts:
TradeToken(ERC-3643): The collateral token.CollateralManagerContract: Transfers collateral to thePayPledge.
Deployment
- Network: Private EVM network (custom Ethereum fork).
- Parameters:
_initialOwner: Address of the Dispute Resolver._payer: Address of the buyer (payer)._erc1155Uri: URI for the ERC-1155 token metadata.