Rayls Docs

Delivery vs Payment (DvP)

DvP is a common financial transaction exchange method where delivery of securities occurs at the same time that payment is made. It ensures that both parties fulfill their obligations simultaneously, reducing counterparty risk and the possibility of default.

Rayls supports two ERC token standards: ERC20 (a standard for creating fungible tokens) and ERC1155 (a standard for creating both fungible and non-fungible tokens).

Overview

The DvP contract allows anyone to create exchanges specifying some parameters (see methods below). Those exchanges are stored on the contract, referenced by their exchangeId, and they can be later executed by the counterparty (unless they are expired). A specific counterparty can be informed on the exchange creation, otherwise, the exchange will be open to any counterparty address to accept it.

Types

enum ExchangeStatus {
  NOT_EXISTS,
  INITIALIZED,
  EXECUTED,
  EXPIRED
}
enum AssetType {
  ERC20,
  ERC1155
}
struct Asset {
  AssetType assetType;
  address tokenAddress;
  uint256 amount;
  uint256 tokenId;
}
struct Exchange {
  address creator;
  Asset creatorAsset;
  address creatorBeneficiary;
  address counterparty;
  Asset counterpartyAsset;
  uint256 expirationDate;
  ExchangeStatus status;
}
  • ExchangeStatus enumerates the possible states the exchange can find itself in.
  • AssetType enumerates the token standards accepted by the contract.
  • Asset defines everything needed to know about an asset used in the exchange.
    • assetType represents the token standard;
    • tokenAddress represents the token's contract address;
    • amount represents the amount offered for the exchange;
    • tokenId is ERC1155-specific and defines the id for the token in the ERC1155 contract.
  • Exchange defines everything that needs to be known about an exchange.
    • creator represents the exchange creator address;
    • creatorAsset represents the Asset the creator is offering in the exchange;
    • creatorBeneficiary represents the address where the exchange creator wants the counterparty funds to be deposited;
    • counterparty represents the exchange acceptor address;
    • counterpartyAsset represents the Asset the counterparty is offering in the exchange;
    • expirationDate represents an expiration date for the exchange to become invalid;
    • status represents the state the exchange finds itself in.

Observations

  • The creator is the exchange initiator , the counterparty is the exchange acceptor.

Properties

uint256 public lastExchangeId;
mapping(uint256 => Exchange) public exchanges;
  • lastExchangeId stores the most recently created exchangeId;
  • exchanges stores a mapping from exchangeIds to exchanges;

Methods

createExchange(
  Asset memory creatorAsset,
  address creatorBeneficiary,
  address counterparty,
  Asset memory counterpartyAsset,
  uint256 expirationDate
)
executeExchange(uint256 exchangeId)
  • The createExchange method should be called by the creator of the exchange.
    • creatorAsset represents the Asset the creator is offering in the exchange;
    • creatorBeneficiary represents the address where the exchange creator wants the counterparty funds to be deposited;
    • counterparty represents the exchange acceptor address;
    • counterpartyAsset represents the Asset the counterparty is offering in the exchange;
    • expirationDate represents an expiration date for the exchange to become invalid;
  • The executeExchange method should be called by the counterparty of the exchange.
    • exchangeId represents the id of the exchange the counterparty wants to accept.

Observations

  • If the creatorBeneficiary address is address(0), then the address used to receive the counterparty funds will be the creator address.
  • If the counterparty address is address(0), then the exchange is open for any counterparty address to accept it.
  • The exchangeId starts as 1 for the first exchange created, and increases by 1 for each following exchange created.

Events

event ExchangeInitialized(
  uint256 indexed exchangeId,
  Exchange exchange
);
event ExchangeExecuted(
  uint256 indexed exchangeId,
  address indexed executor
);
  • When the createExchange method is concluded successfully, the ExchangeInitialized event will be emitted.
  • When the executeExchange method is concluded successfully, the ExchangeExecuted event will be emitted.

Errors

'DvPExchange.createExchange: INVALID_EXPIRATION_DATE'
'DvPExchange.createExchange: INVALID_EXCHANGE_ID'
'DvPExchange.createExchange: INSUFFICIENT_ALLOWANCE'
'DvPExchange.createExchange: INSUFFICIENT_BALANCE'
'DvPExchange.createExchange: NOT_APPROVED_FOR_ALL'
'DvPExchange.createExchange: INVALID_ASSET_TYPE'

'DvPExchange.executeExchange: EXCHANGE_NOT_INITIALIZED'
'DvPExchange.executeExchange: EXCHANGE_EXPIRED'
'DvPExchange.executeExchange: UNAUTHORIZED_SENDER'
'DvPExchange.executeExchange: INVALID_ASSET_TYPE for creator'
'DvPExchange.executeExchange: INVALID_ASSET_TYPE for counterparty'
'DvPExchange.executeExchange: TRANSFER_FAILED'
  • createExchange
    • DvPExchange.createExchange: INVALID_EXPIRATION_DATE occurs when you try to create an exchange with an expiration date in the past (that is, trying to create an exchange that would be born already expired).
    • DvPExchange.createExchange: INVALID_EXCHANGE_ID occurs in the extremely exceptional case where the exchangeIds overflow the uint256
    • DvPExchange.createExchange: INSUFFICIENT_ALLOWANCE occurs when the creator uses an ERC20 token and hasn't allowed the DvP contract to use enough funds to supply the exchange demand they are trying to create.
    • DvPExchange.createExchange: INSUFFICIENT_BALANCE occurs when the creator uses any token and they don't have enough balance to supply the exchange demand they are trying to create.
    • DvPExchange.createExchange: NOT_APPROVED_FOR_ALL occurs when the creator uses an ERC1155 token and hasn't approved the DvP contract to use funds to supply the exchange demand they are trying to create.
    • DvPExchange.createExchange: INVALID_ASSET_TYPE occurs when the AssetType informed in the creatorAsset is invalid.
  • executeExchange
    • DvPExchange.executeExchange: EXCHANGE_NOT_INITIALIZED when the exchange status is not initialized (and thus it's not ready to be accepted).
    • DvPExchange.executeExchange: EXCHANGE_EXPIRED when the exchange is already expired.
    • DvPExchange.executeExchange: UNAUTHORIZED_SENDER when the acceptor, who is trying to execute the exchange, is not the one determined by the creator.
    • DvPExchange.executeExchange: INVALID_ASSET_TYPE for creator when the AssetType informed in the creatorAsset is invalid.
    • DvPExchange.executeExchange: INVALID_ASSET_TYPE for counterparty when the AssetType informed in the counterpartyAsset is invalid.
    • DvPExchange.executeExchange: TRANSFER_FAILED when it is an ERC20 transfer and the transfer fails.