Logo
    đź’ľ

    Market/deal contract interfaces notes

    Creator
    Alex North
    Created
    Feb 9, 2022 12:34 PM
    Project
    Storage Programmability
    Stage
    Graduated from Notebook

    This note is a scratchpad for contract API standards in an open, composable storage market.

    See also đź’ľArchitecture for programmable storage markets, which improves some pieces here.

    Ethereum token standards for reference

    Origin of ERCs: https://github.com/ethereum/EIPs/issues/16

    https://docs.soliditylang.org/en/v0.8.10/abi-spec.html

    https://www.nftstandards.wtf/NFT+Standards+Wiki+-+READ.me

    https://www.azuki.com/erc721a

    Market/Deal standard interface

    Extend ERC721 to deals.

    Expose properties as methods rather than the DealProposal struct to abstract over representations, allow other markets to have other proposal data.

    These data are not necessarily immutable.

    Deal lifecycle state.

    TODO: add an opaque string that markets can use to communicate additional info?

    // Returns NotStarted, Active, Faulty, Terminated, Completed
    function dealState(tokenId) return DealStateEnum

    Market API for storage providers (the miner actor) to call to

    • Support maintaining sector→deal mappings
    • Support faults

    TODO: Market API for deal clients?

    Not sure that this should be standard: markets might have quite different inputs or mechanisms.

    Miner API

    function sectorSealedCID(sectorId) return CID
    function sectorTerm(sectorId) return {activation: epoch, expiration: epoch}
    
    // This is externalises Window PoSt status.
    // Caller must know the sector deadline/partition (from an off-chain index).
    // Return values are live, faulty, recovering, terminated.
    function sectorState(sectorId, deadline, partition) return SectorStateEnum

    FIL+ API?

    FIL+ system that other markets can broker deals for too.

    Somewhat independent of whether FIL+ premium is implemented, though details will vary.

    TODO: possibly attempt a standard for other deal incentivisation schemes to implement too? But maybe premature. It’s ok for markets and incentive schemes to explicitly code for each other.

    CryptoNet is a Protocol Labs initiative.

    // ERC-20
    function name() public view returns (string) // opt
    function symbol() public view returns (string) // opt
    function decimals() public view returns (uint8) // opt
    function totalSupply() public view returns (uint256)
    function balanceOf(address _owner) public view returns (uint256 balance)
    function transfer(address _to, uint256 _value) public returns (bool success)
    function transferFrom(address _from, address _to, uint256 _value) public returns (bool success)
    function approve(address _spender, uint256 _value) public returns (bool success)
    function allowance(address _owner, address _spender) public view returns (uint256 remaining)
    // ERC-721
    function balanceOf(address _owner) external view returns (uint256)
    function ownerOf(uint256 _tokenId) external view returns (address)
    function safeTransferFrom(address _from, address _to, uint256 _tokenId, bytes data) external payable
    function safeTransferFrom(address _from, address _to, uint256 _tokenId) external payable
    function transferFrom(address _from, address _to, uint256 _tokenId) external payable
    function approve(address _approved, uint256 _tokenId) external payable
    function setApprovalForAll(address _operator, bool _approved) external
    function getApproved(uint256 _tokenId) external view returns (address)
    function isApprovedForAll(address _owner, address _operator) external view returns (bool)
    
    // ERC721Metadata (optional)
    function name() external view returns (string _name)
    function symbol() external view returns (string _symbol)
    function tokenURI(uint256 _tokenId) external view returns (string)
    
    // ERC721Enumerable (optional)
    function totalSupply() external view returns (uint256)
    function tokenByIndex(uint256 _index) external view returns (uint256)
    function tokenOfOwnerByIndex(address _owner, uint256 _index) external view returns (uint256)
    
    // ERC-165 (required by ERC-721)
    function supportsInterface(bytes4 interfaceID) external view returns (bool)
    
    // ERC721TokenReceiver
    function onERC721Received(address _operator, address _from, uint256 _tokenId, bytes _data) external returns(bytes4)
    // Returns proposal PieceCID
    // For the multi-part deals this would be the root CID
    // For capacity deals, this would be the data most recently committed
    function dealPieceCID(tokenId) returns (CID) 
    
    // Padded size of data (piece/s)
    function dealSize(tokenId) returns uint64
    
    // Current provider. Note: client is the ERC-721 owner.
    function dealProvider(tokenId) returns Address
    
    // Arbitrary client-provided label.
    function dealLabel(tokenId) returns string
    
    function dealTerm(tokenId) return {start: epoch, end: epoch}
    
    function dealPricePerEpoch(tokenId) return TokenAmount
    
    function dealCollateral(tokenId) return {provider: TokenAmount, client: TokenAmount}
    
    // Note
    // IsVerified is not here – registration with incentive schemes belongs with the scheme
    // Inform market that a deal with data has been activated in a sector.
    // Possibly replacing previous data. 
    // All still-current deals should be specified.
    // Miner code is trusted to report correct PieceCID/CommD.
    // TODO: batch call for many sectors
    type SectorDeal {
    	dealId int
    	pieceCID CID
    }
    // Market must look up deal piece CIDs, check match.
    // Terminate any deals previously recorded for the sector that aren't re-proven.
    // NOTE: if QAP, deals can only be new deals put in previously-zero space.
    // After QAP, miner should specify all deals?
    function sectorContentUpdate(sectorId, deals []SectorDeal)
    
    // Inform market that sector faulted/recovered.
    // Called via a miner/market subscription mechanism.
    function sectorFault(sectorId...)
    function sectorRecovered(sectorId...)
    ///// API for markets
    type VerifiedDealData {
    	client Address
    	provider Address
    	piece CID
    	size uint64
      start epoch
    	end epoch
    	label string // to disambiguate multiples
    }
    
    // Called by market when a deal is published.
    // The client signs the VDD as a data cap authorization, 
    // reducing necessary trust of the market.
    // Deducts data cap for client (or fails).
    function dealPublished(marketId, dealId, vdd, clientSignature) return bool
    
    // Restores data cap for client after deal wasn't consumated.
    // Deal start epoch must have passed.
    // Should be called by market, but could be by anyone.
    function dealFailed(marketId, dealId)
    
    
    ///// API for third parties
    function dealIsVerified(marketId, dealId) return bool
    function verifiedDealData(marketId, dealId) return VerifiedDealData
    
    
    ///// API for miners - retaining QAP
    
    // Called by miner to get information for computing QAP (we trust the miner code).
    // Miner must activate deals first, then pass activated deals IDs here.
    // Miner must check inclusion of each piece CID in CommD (which it will do anyway
    // for deal activation).
    // Deals may come from multiple markets.
    function verifiedDealData(marketDealIds...) return []VerifiedDealData
    
    ///// API for miners - FIL+ premium
    
    // If we do FIL+ premium reward accounting in the FIL+ actor 
    // (instead of replicating it in each market)
    // it needs to know about sector->deal mapping and sector content updates.
    
    // Activates deal, which will earn premium from its start epoch
    function dealActivated(marketId, dealId, sectorId)
    // Terminates deal early, paying penalties from pledge held by FIL+ 
    function dealTerminated(marketId, dealId)
    function sectorFaulty(sectorId)
    function sectorRecovered(sectorId)