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
// 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)
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.
// 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
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
// 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...)
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.
///// 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)