0xProject / ZEIPs

0x Improvement Proposals
Apache License 2.0
91 stars 15 forks source link

Utility Extension #44

Closed feuGeneA closed 4 years ago

feuGeneA commented 5 years ago

Summary

Proposed is a new protocol extension contract providing various utility functions to improve the experience of building on top of the 0x contracts. Specifically, this contract will provide an asset data encoder/decoder, an order validator, and a transaction decoder.

Motivation

To reduce the barrier to entry for new development environments (new languages, etc), we will expose a number of on-chain helper and verification functions. With these functions, any language that can call into the EVM can get started with 0x quickly, without having to reimplement common logic.

Regarding the transaction decoder, in the specification of the WebSocket API for interfacing with a Coordinator server, having functionName and orders is redundant, because that information is already included in signedTransaction.data. However, those fields were left in for the time being, since decoding that data is not particularly easy. This extension will provide convenience methods for decoding that data.

Specification

Asset Data Encoding/Decoding

Asset data encoding/decoding functionality will not only allow callers to determine what assets are specified by a given asset data string, but it will also provide callers the ability to query balances and allowances, both for single orders and for batches, using solely asset data (and owner) as the input.

/// @dev Returns the owner's balance of the token(s) specified in
///     assetData.  When the asset data contains multiple tokens (eg in
///     ERC1155 or Multi-Asset), the return value indicates how many
///     complete "baskets" of those tokens are owned by owner.  For
///     example, if assetData specifies 10 ZRX and 3 WETH, and owner holds
///     20 ZRX and 6 WETH, then this function will return 2.
/// @param owner Owner of the tokens specified by assetData.
/// @param assetData Description of tokens, per the AssetProxy contract
///     specification.
/// @return Number of tokens (or token baskets) held by owner.
function getBalance(address owner, bytes memory assetData)
    public view returns (uint256 balance)

/// @dev Calls getBalance() for each element of assetData.
/// @param owner Owner of the tokens specified by assetData.
/// @param assetData Array of token descriptors, each encoded per the
///     AssetProxy contract specification.
/// @return Array of token balances from getBalance(), with each element
///     corresponding to the same-indexed element in the assetData input.
function getBatchBalances(address owner, bytes[] memory assetData)
    public view returns (uint256[] memory balances)

/// @dev Returns the number of token(s) (described by assetData) that
///     spender is authorized to spend.  When the asset data contains
///     multiple tokens (eg for Multi-Asset), the return value indicates
///     how many complete "baskets" of those tokens may be spent by
///     spender.  For example, if assetData specifies 10 ZRX and 3 WETH,
///     and owner holds 20 ZRX and 6 WETH, then this function will return
///     2.
/// @param owner Owner of the tokens specified by assetData.
/// @param spender Address whose authority to spend is in question.
/// @param assetData Description of tokens, per the AssetProxy contract
///     specification.
/// @return Number of tokens (or token baskets) that the spender is
///     authorized to spend.
function getAllowance(address owner, address spender, bytes memory assetData)
    public view returns (uint256 allowance)

/// @dev Calls getAllowance() for each element of assetData.
/// @param owner Owner of the tokens specified by assetData.
/// @param spender Address whose authority to spend is in question.
/// @param assetData Description of tokens, per the AssetProxy contract
///     specification.
/// @return An array of token allowances from getAllowance(), with each
///     element corresponding to the same-indexed element in the assetData
///     input.
function getBatchAllowances(
    address owner,
    address spender,
    bytes[] memory assetData
)
    public view returns (uint256[] memory allowances)

/// @dev Calls getBalance() and getAllowance() for assetData.
/// @param owner Owner of the tokens specified by assetData.
/// @param spender Address whose authority to spend is in question.
/// @param assetData Description of tokens, per the AssetProxy contract
///     specification.
/// @return Number of tokens (or token baskets) held by owner, and number
///     of tokens (or token baskets) that the spender is authorized to
///     spend.
function getBalanceAndAllowance(
    address owner,
    address spender,
    bytes memory assetData
)
    public view returns (uint256 balance, uint256 allowance)

/// @dev Calls getBatchBalances() and getBatchAllowances() for each element
///     of assetData.
/// @param owner Owner of the tokens specified by assetData.
/// @param spender Address whose authority to spend is in question.
/// @param assetData Description of tokens, per the AssetProxy contract
///     specification.
/// @return An array of token balances from getBalance(), and an array of
///     token allowances from getAllowance(), with each element
///     corresponding to the same-indexed element in the assetData input.
function getBatchBalancesAndAllowances(
    address owner,
    address spender,
    bytes[] memory assetData
)
    public view returns (
        uint256[] memory balances,
        uint256[] memory allowances
    )

/// @dev Encode ERC-20 asset data into the format described in the
///     AssetProxy contract specification.
/// @param tokenAddress The address of the ERC-20 contract hosting the
///     token to be traded.
/// @return AssetProxy-compliant data describing the asset.
function encodeERC20AssetData(address tokenAddress)
    public pure returns (bytes memory assetData)

/// @dev Decode ERC-20 asset data from the format described in the
///     AssetProxy contract specification.
/// @param assetData AssetProxy-compliant asset data describing an ERC-20
///     asset.
/// @return The ERC-20 AssetProxy identifier, and the address of the ERC-20
///     contract hosting this asset.
function decodeERC20AssetData(bytes memory assetData)
    public pure returns (
        bytes4 proxyId,
        address tokenAddress
    )

/// @dev Encode ERC-721 asset data into the format described in the
///     AssetProxy specification.
/// @param tokenAddress The address of the ERC-721 contract hosting the
///     token to be traded.
/// @param tokenId The identifier of the specific token to be traded.
/// @return AssetProxy-compliant asset data describing the asset.
function encodeERC721AssetData(address tokenAddress, uint256 tokenId)
    public pure returns (bytes memory assetData)

/// @dev Decode ERC-721 asset data from the format described in the
///     AssetProxy contract specification.
/// @param assetData AssetProxy-compliant asset data describing an ERC-721
///     asset.
/// @return The ERC-721 AssetProxy identifier, the address of the ERC-721
///     contract hosting this asset, and the identifier of the specific
///     token to be traded.
function decodeERC721AssetData(bytes memory assetData)
    public pure returns (
        bytes4 proxyId,
        address tokenAddress,
        uint256 tokenId
    )

/// @dev Encode ERC-1155 asset data into the format described in the
///     AssetProxy contract specification.
/// @param tokenAddress The address of the ERC-1155 contract hosting the
///     token(s) to be traded.
/// @param tokenIds The identifiers of the specific tokens to be traded.
/// @param tokenValues The amounts of each token to be traded.
/// @param callbackData ...
/// @return AssetProxy-compliant asset data describing the set of assets.
function encodeERC1155AssetData(
    address tokenAddress,
    uint256[] memory tokenIds,
    uint256[] memory tokenValues,
    bytes memory callbackData
)
    public pure returns (bytes memory assetData)

/// @dev Decode ERC-1155 asset data from the format described in the
///     AssetProxy contract specification.
/// @param assetData AssetProxy-compliant asset data describing an ERC-1155
///     set of assets.
/// @return The ERC-1155 AssetProxy identifier, the address of the ERC-1155
///     contract hosting the assets, an array of the identifiers of the
///     tokens to be traded, an array of token amounts to be traded, and
///     callback data.  Each element of the arrays corresponds to the
///     same-indexed element of the other array.  Return values specified as
///     `memory` are returned as pointers to locations within the memory of
///     the input parameter `assetData`.
function decodeERC1155AssetData(bytes memory assetData)
    public pure returns (
        bytes4 proxyId,
        address tokenAddress,
        uint256[] memory tokenIds,
        uint256[] memory tokenValues,
        bytes memory callbackData
    )

/// @dev Encode data for multiple assets, per the AssetProxy contract
///     specification.
/// @param amounts The amounts of each asset to be traded.
/// @param nestedAssetData AssetProxy-compliant data describing each asset
///     to be traded.
/// @return AssetProxy-compliant data describing the set of assets.
function encodeMultiAssetData(
    uint256[] memory amounts,
    bytes[] memory nestedAssetData
)
    public pure returns (bytes memory assetData)

/// @dev Decode multi-asset data from the format described in the
///     AssetProxy contract specification.
/// @param assetData AssetProxy-compliant data describing a multi-asset
///     basket.
/// @return The Multi-Asset AssetProxy identifier, an array of the amounts
///     of the assets to be traded, and an array of the
///     AssetProxy-compliant data describing each asset to be traded.  Each
///     element of the arrays corresponds to the same-indexed element of
///     the other array.
function decodeMultiAssetData(bytes memory assetData)
    public pure returns (
        bytes4 proxyId,
        uint256[] memory amounts,
        bytes[] memory nestedAssetData
    )

Order Validator

The order validation functionality will provide some conveniences for helping to verify the validity of orders.

struct TraderInfo {
    uint256 makerBalance;       // Maker's balance of makerAsset
    uint256 makerAllowance;     // Maker's allowance to corresponding AssetProxy
    uint256 takerBalance;       // Taker's balance of takerAsset
    uint256 takerAllowance;     // Taker's allowance to corresponding AssetProxy
    uint256 makerZrxBalance;    // Maker's balance of ZRX
    uint256 makerZrxAllowance;  // Maker's allowance of ZRX to ERC20Proxy
    uint256 takerZrxBalance;    // Taker's balance of ZRX
    uint256 takerZrxAllowance;  // Taker's allowance of ZRX to ERC20Proxy
}

/// @dev Fetches information for order and maker/taker of order.
/// @param order The order structure.
/// @param takerAddress Address that will be filling the order.
/// @return OrderInfo and TraderInfo instances for given order.
function getOrderAndTraderInfo(
    LibOrder.Order memory order,
    address takerAddress
)
    public
    view
    returns (
        LibOrder.OrderInfo memory orderInfo,
        TraderInfo memory traderInfo
    )

/// @dev Fetches information for all passed in orders and the makers/takers
///     of each order.
/// @param orders Array of order specifications.
/// @param takerAddresses Array of taker addresses corresponding to each
///     order.
/// @return Arrays of OrderInfo and TraderInfo instances that correspond to
///     each order.
function getOrdersAndTradersInfo(
    LibOrder.Order[] memory orders,
    address[] memory takerAddresses
)
    public
    view
    returns (
        LibOrder.OrderInfo[] memory ordersInfo,
        TraderInfo[] memory tradersInfo
    )

/// @dev Fetches balance and allowances for maker and taker of order.
/// @param order The order structure.
/// @param takerAddress Address that will be filling the order.
/// @return Balances and allowances of maker and taker of order.
function getTraderInfo(LibOrder.Order memory order, address takerAddress)
    public
    view
    returns (TraderInfo memory traderInfo)

/// @dev Fetches balances and allowances of maker and taker for each
///     provided order.
/// @param orders Array of order specifications.
/// @param takerAddresses Array of taker addresses corresponding to each
///     order.
/// @return Array of balances and allowances for maker and taker of each
///     order.
function getTradersInfo(
    LibOrder.Order[] memory orders,
    address[] memory takerAddresses
)
    public
    view
    returns (TraderInfo[] memory)

/// @dev Calls `token.ownerOf(tokenId)`, but returns a null owner instead
///     of reverting on an unowned token.
/// @param token Address of ERC721 token.
/// @param tokenId The identifier for the specific NFT.
/// @return Owner of tokenId or null address if unowned.
function getERC721TokenOwner(address token, uint256 tokenId)
    public
    view
    returns (address owner)

Transaction Decoder

/// @dev Decodes the call data for an Exchange contract method call.
/// @param signedTransactionData ABI-encoded calldata for an Exchance
///     contract method call.
/// @return The name of the function called, and the parameters it was
///     given.  For single-order fills and cancels, the arrays will have
///     just one element.
function decodeTransaction(bytes memory signedTransactionData)
    public
    view
    returns(
        string memory functionName,
        LibOrder.Order[] memory orders,
        uint256[] memory takerAssetFillAmounts,
        bytes[] memory signatures
    )