OpenChrono
  • OpenChrono Docs
  • About OpenChrono.io
    • What is OpenChrono?
    • Digital Twins & TimePiece Passports™
    • OpenChrono Architecture
    • Authentication Standards
    • Authentication Process
    • Our Team
    • Our Partners
  • Product Tour
    • Marketplace
    • Platform Navigation
      • Search For A Watch
      • Buy A Watch
      • Sell A Watch
      • Redeem A Watch
      • Account Wallets
      • Lending
    • Platform Fees
    • Payment Methods
    • Vault Your Watch
    • Buyer Protection
    • Seller Protection
  • Platform Technical Info
    • Smart Contracts
    • TimePiece Passport™ Tech
    • Royalties
    • Escrow Lifecycle
    • Contract Addresses
    • Minting
    • Creating A Digital Twin
    • Document Updates
    • Metadata Format
    • Deploying & Upgrading
    • Fee Structure
  • Logistics & Legal
    • Secure Vaults & Insurance
    • KYC / AML Checks
    • Last Mile Delivery
  • User Agreement
    • Users Terms of Service
    • Website Terms of Service
    • Privacy & Cookie Notice
  • Resources
    • WhitePaper
      • Untitled
      • Page 1
    • Useful Links
    • Careers
    • Investments & Funding
    • About OpenChrono
Powered by GitBook
On this page
  • Setting the price
  • Starting an Escrow
  • Finalising an Escrow
  • Handling Failed Payment
  • Expire Time & Finalisers
  • Redeeming a Token
  • Cancelling an Order

Was this helpful?

  1. Platform Technical Info

Escrow Lifecycle

Last updated 1 year ago

Was this helpful?

A token is escrowed once all the checkout information is submitted on the website.

Escrowing a token means that the token will be transferred from the seller to the escrow contract. The main goal of this is so that the 'digital twin' cannot be transferred to another wallet during the payment process. When the payment is completed the token and ownership is transferred to the buyer.

The image below shows how the contracts play a role in both crypto and fiat payments.

Setting the price

When a seller is creating a new listing, a TokenListingData instance is created and mapped to the token ID.

struct TokenListingData {
  address sellerAddress;
  /// @notice The seller set price of the watch. The seller fees are taken from this
  ///         and the buyer fees are added to it.
  ///         The base price is always in USDC.
  ///         If a token has 6 decimals (see the token's decimals() function)
  ///         and the total price would be 870.34 of that token, then the value of this
  ///         parameter would be 870340000.
  uint256 basePrice;
  /// @notice The contract address of the token to pay with.
  ///         Normally this is always the USDC address.
  ///         If this value is address(0) then it is interpreted as the
  ///         native token. This also means that the buyer has to set
  ///         msg.value == price
  ///         If the value is address(1) then it is interpreter as a
  ///         FIAT payment. (address(1) is a reserved address in the EVM).
  address paymentTokenAddress;
}

The reason for reserving an address for fiat payments is so that a buyer can not start a crypto payment during a fiat payment process. While the chances of this happening, and the impact that it has, are not very large, having this strict blocker avoids extra management of payment processes.

The price to set is in the smallest denomination of the payment token. For example. If the price is $15000,10 and the the exchange rate between USDC and USD is 0,980000 USDC per $1 USD (note that USDC has 6 decimals), the price to set for a crypto payment with USDC would be 15000,10 * 0,980000 = 14700,098000 USDC. So the parameters would be a price of 14700098000 and the payment token address being the address of the USDC token.

The price set in the listing data is used when the buyer is buying the watch.

Once the seller is happy with the listing, they will be asked to send a transaction to the TimePieceEscrow contract to set the listing data using the following function:

/// @notice Sets the listing data for a token. The price and payment token can be updated
///         as long as the token is not escrowed.
///         Only the token owner can be the seller and can call this function.
function setListingData(
    uint256 tokenId,
    TokenListingData calldata tokenListingData
) external;

The seller can call this function as often as desired to update the price as long as the seller is the owner of the token. If the seller transfers the token to another address, the listing data is effectively invalidated.

Starting an Escrow

When starting an escrow, some information about the order is required. All this information is in the TokenEscrowData struct.

struct TokenEscrowData {
  address buyerAddress;
  /// @notice If this field is set to true the token soulbound to the buyer after
  ///         the escrow is successfully finalised.
  bool redeeming;
  /// @notice This time indicates the time in seconds (block.timestamp format)
  ///         at which the escrow is expired.
  uint256 expireTime;
  /// @notice The escrowed is used to uniquely identify an escrow.
  string escrowId;
}

An escrow can only be started by OpenChrono and is started by calling the following function:

/// @notice Starts the token escrow process and transfers the
///         token from the seller to this contract.
/// @param tokenId The token ID that is being bought.
/// @param tokenEscrowData A filled struct of type TokenEscrowData
///        that contains all needed data for handling the escrow process.
function startTokenEscrow(
    uint256 tokenId,
    TokenEscrowData calldata tokenEscrowData
) external;

Finalising an Escrow

When the payment is completed, the escrow can be finalised by a trusted address by calling the following functions:

/// @notice If the payment was successful, the token can be transferred to the buyer
///         and the escrow data can be deleted.
///         This function can only be called by an address from the `finaliserAddresses`
///         array that tokenId maps to.
function paymentSucceeded(uint256 tokenId) external;

For digital asset payments this is called in the same transaction as buying the watch.

Handling Failed Payment

A failed crypto transaction will simply undo all changes made during the transaction, meaning, it is as if the payment attempt never happened.

Similar with fiat payments. These payments are conducted outside the contract. So as long as the payments can be retried, the contracts are not affected.

If either the fiat or crypto payment can not be completed for whatever reason, the buyer may change the payment method. This means that switching between fiat and crypto payments is allowed.

Expire Time & Finalisers

The escrow contract has a set of finalisers. Finalisers are addresses that are allowed to indicate that a payment succeeded or failed before the expiration time expired. By default these are the TimePiecePayment contract and the OpenChrono backend wallet.

The expiration time indicates when an escrow took too long. After the expiration, anyone can finalise the expired escrow. Finalising this way is similar to having a failed payment in the sense that the token is transferred back to the seller.

Redeeming a Token

When buying a watch the buyer has the option to redeem the watch as well.

Cancelling an Order

If a buyer decides to resign from the order, a finaliser can let the TimePieceEscrow contract know that the payment has failed. This will send the token back to the seller. Another, less optimal, way would be to wait for the expiration time so that anyone can cancel the escrow.

When a finaliser indicates that the payment was successful for a redeeming token, the token is made soul-bound (following the standard) to the buyer.

ERC-5192
OpenChrono 'Escrow Contract' Overview