SubContract API Reference

API reference for the solidity SubContract interface, as well as explanations of functions/types and external links to implementation examples.

Full interface

The minimum required interface for a valid SubContract is included below. See the next section for detailed descriptions of each function.

interface SubContract {

    // returns required makerArguments
    function makerArguments() external view returns (string memory);

    // returns required takerArguments
    function takerArguments() external view returns (string memory);

    // validation implementation
    function isValid(bytes32[] calldata) external view returns (bool);

    // implementation of remaining availability accounting method supporting partial fill
    function amountRemaining(bytes32[] calldata) external view returns (uint);

    // primary settlement implementation
    function participate(bytes32[] calldata, bytes32[] calldata) external returns (bool);
}

Function interfaces

Detailed descriptions of each required function interface for a SubContract implementation.

makerArguments()

  • Required interface:

    function makerArguments() external view returns (string memory);
    
  • Description:

    The takerArguments() function allows access to the maker arguments definitions for a specific SubContract. This method can be implemented in a variety of manners, so long as it returns the expected data structure that defines required values for makers.

    The definitions are necessary to support the settlement implementation. This method is leveraged by paradigm-connect to validate maker orders and check for required fields.

  • Return conditions:

    Should return makerArguments for the SubContract, according to the arguments data structure defined here.

takerArguments()

  • Required interface:

    function takerArguments() external view returns (string memory);
    
  • Description:

    The takerArguments() function allows access to the taker arguments definitions for a specific SubContract. This method can be implemented in a variety of manners, so long as it returns the expected data structure that defines required values for takers.

    The definitions are necessary to support the settlement implementation. This method is leveraged by paradigm-connect to validate taker requests and check for required fields.

  • Return conditions:

    Should return takerArguments for the SubContract, according to the arguments data structure defined here.

participate()

  • Required interface:

    function participate(
        bytes32[] memory makerData,
        bytes32[] memory takerData
    ) public returns (bool)
    
  • Description:

    The participate() function will be called to initiate the financial exchange transaction. It is the primary implementation of a SubContract's settlement logic. The contract creator is going to be responsible for transforming the input bytes32 more appropriate types based on the maker and taker arguments they have defined. After a successful exchange a boolean true may be returned (see below).

    The participate() function can be implemented with any logic in the function body required to execute – "participate" in – your specific settlement logic. For native SubContracts, this would likely be where the execution of your settlement logic takes place. For wrapping SubContracts, it is likely where parsing/validation/formatting will take place, after which an external call will actually execute the settlement logic.

  • Return conditions:

    • true if the execution completed successfully.
    • false if the execution failed for any reason.
  • Remarks:

    You can view an implementation of participate() in the 0x v2 example SubContract, found here.

isValid()

  • Required interface:

    function isValid(
      bytes32[] memory makerData
    ) public view returns (bool)
    
  • Description:

    The isValid() function will be called to determine if an order is valid. The function should transform the input data then run validation to determine if the order still has available balances to exchange and is signed correctly.

    You may implement whatever you choose in isValid(), depending on the specific settlement logic implementation. Ideally, the function will perform as much validation as possible, and if true is returned, one would expect that participate() called with proper arguments would also return true.

  • Return conditions:

    • true if the "order" (or makerData) is valid or has an amount remaining.
    • false if makerData validation failed, or is invalid for any other reason.
  • Remarks:

    You can view an implementation of isValid() in the 0x v2 example SubContract, found here.

amountRemaining()

  • Required interface:

    function amountRemaining(
      bytes32[] memory makerData
    ) public view returns (uint)
    
  • Description:

    The amountRemaining() function will be called to determine how many tokens are still available. The function should take the maker information and use the internal accounting to look up how many of the offered tokens remain unclaimed.

    The implementation of this function will differ depending on various settlement types. For example, this function is particularly useful for order/settlement types that allow "partial-fills", in which an amount less than the maker total may be taken at any time, such as most 0x orders. If a settlement type does not support partial fills, amountRemaining() may just return the full order amount.

  • Return conditions:

    The return value of participate() is a uint, and should reflect whatever the "amount remaining" means for a given settlement logic implementation. If a settlement type has no notion of "amount remaining" or partial-fills in general, it can return the full order amount.

  • Remarks:

    You can view an implementation of amountRemaining() in the 0x v2 example SubContract, found here.

Examples and references

Further reference, and explanation of dependant/expected data structures.

Maker/Taker Arguments

As discussed above, makerArguments and takerArguments facilitate the conversion between human-readable JSON-like formats, and the actual Solidity data types required for SubContract implementation.

The basic format is:

const makerArguments = [
    // ...
    {
        "dataType": "address",      // can be any valid fixed size solidity type
        "name":     "makerAddress"  // the name of the key to be used in makerValues
    },
    // ...
];

There should be as many maker/taker argument definitions as there are maker/taker values defined in your SubContract. For example, every 0x order requires the following fields:

// TypeScript show, for illustrative purposes. Solidity types differ (see below)

const makerAddress: string;         // maker's ETH address
const takerAddress: string;         // taker's ETH address
const makerFee: string;             // fee specified from maker
const takerFee: string;             // fee specified from taker
const senderAddress: string;        // sender (submitter) of the order
const makerAssetAmount: string;     // amount maker is offering
const takerAssetAmount: string;     // amount maker is requesting from taker
const makerAssetData: string;       // asset data (encoded) for maker token
const takerAssetData: string;       // asset data (encoded) for taker token
const salt: string;                 // pseudo-random salt
const exchangeAddress: string;      // 0x exchange address (per networkId)
const feeRecipientAddress: string;  // address that will receive maker/taker fees
const expirationTimeSeconds: string;// UNIX timestamp (seconds) of order expiry 

The above would end up as makerValues in a Paradigm Order object, with the following used as makerArguments (note this is the actual definition for the 0x v2 SubContract):

JSON format is show below, can be "stringified" as well for contract transport.

[
  {'dataType': "address", 'name': "makerAddress" },
  {'dataType': "address", 'name': "takerAddress" },
  {'dataType': "address", 'name': "feeRecipientAddress" },
  {'dataType': "address", 'name': "senderAddress" },
  {'dataType': "uint", 'name': "makerAssetAmount" },
  {'dataType': "uint", 'name': "takerAssetAmount" },
  {'dataType': "uint", 'name': "makerFee" }, 
  {'dataType': "uint", 'name': "takerFee" }, 
  {'dataType': "uint", 'name': "expirationTimeSeconds" },
  {'dataType': "uint", 'name': "salt" },
  {'dataType': "bytes32", 'name': "makerAssetData0" },
  {'dataType': "bytes32", 'name': "makerAssetData1" },
  {'dataType': "bytes32", 'name': "takerAssetData0" }, 
  {'dataType': "bytes32", 'name': "takerAssetData1" },
  {'dataType': "bytes32", 'name': "signature0" },
  {'dataType': "bytes32", 'name': "signature1" },
  {'dataType': "bytes32", 'name': "signature2" },
  {'dataType': "address", 'name': "exchangeAddress" },
]

In solidity SubContract implementations, the makerArguments and takerArguments can (and should) be stored with the string type.

Additional Examples

The 0x v2 SubContract is mentioned here several times, you can find it's source (and documentation) at the following links: