Closed dekz closed 4 years ago
This ZEIP is needed by NFT open finance. By allowing the maker to supply a predicate, we are making subsets of NFTs fungible(i.e. buy any axie with plant attribute or any 10x10 plot on Maldives) which allows for traditional order books on these specific subsets creating price support due to volume in limit orders. This is a needed step to create NFT markets that can be used in defi protocols such as Maker CDPs, Dharma Loans, etc.
Match Orders makes sense for this use case.
In addition to the following use cases: 1 DAI for an Axie 100 DAI for 100 Axies
We would also be able to sign orders such as: 1000 DAI for any decentraland parcel located inside x(-20,20) and y(10,30) 100 dai for 10 Axies with the gen 0 attribute
Been thinking about this recently from the perspective of V3. I think we could pull this off with a small change to matchOrders()
and by using the new Validator
signature type (#33).
The idea is to exploit the fact that matchOrders()
already copies the mirrored asset data of the leftOrder
into the rightOrder
before signature validation (we expect it to fail if the orders are not complementary). Thus, if rightOrder
uses a Validator
signature type, its callback will receive the full order with the asset data supplied by leftOrder
. rightOrder
can then validate that takerAssetData
is an NFT that fits its criterion.
This actually sort of works right now, but because the order hash will be different for every fill, rightOrder
's filled
state never updates, so a taker could keep filling this order until it expires or is cancelled. So we need to update matchOrders()
to use the original order hash when updating the filled
state, and the updated order hash (with the mirrored asset data) for everything else.
There is some extra data you would need to encode in the order signature for safety and maybe flexibility, but I don't think it's too bad.
I've been thinking about this in light of #74. What is being proposed here are ways to make it work with minimal changes to the existing exchange, mostly using matchOrders
. But the proposals feel like hacks to me. What we are dealing with is not a new order type or a new settlement function, but a generalization of the asset string mechanism.
Also consider that this not only applies to order.takerAssetData
(i.e.: I'm willing to buy any yellow cryptokitty) but also to order.makerAssetData
(i.e. I'm willing to sell any beginner deck card), or even maker/takerFeeAssetData
(10 ZRXs for the first to come up with a good usecase).
We also need to think carefuly about how it changes the meaning of *AssetAmount
. Rounding, prices and limits are harder to define. It would be fun to have a predicate for 'USDC or DAI', but if you want to include non-USD pegged stablecoins in the mix you need different prices. But if are taking the generality that far that we might as well replace the entire maker order by a big maker-signed predicate that answers 'is this trade acceptable to you?'. Probably don't want to go there. (Or do we?)
Anyway,
Currently the maker fully specifies the allowed assets for the trade on signing. What we want here is that instead the maker signs a predicate that defines what allowable assets are. The maker part of this is easy, we can add a new asset id that specifies the predicate and use that as the asset string. Where we currently have an asset strings like ERC721(<contract address>, <token id>)
we would create a new asset string that encodes Predicate(<contract address>, <extra data>)
. The contract at specified address would then implement some interface like satisfiesPredicate(<extra data>, <taker asset id>)
which the exchange or asset proxy would have to call. The <extra data>
is just there so you don't need to deploy a new contract every time, but can instead program in some reusable generality.
So far so good, the problems start with the <taker asset id>
. Currently we simply take the asset strings from maker's order and apply those to taker. To implement this correctly we need to allow taker to supply it's own asset strings. We may even want taker to supply additional data to convince the predicate (like 'here's a merkle proof that this cryptokitty is indeed yellow like you want'). The current contracts are not designed for this. The only thing taker provides is evidence that it wants this trade to happen (the signature) not how it should happen. That said, without major changes to the protocol, it is the only place where taker can say anything at all, and none of this information except amounts and taker address is passed into the asset proxy.
So it seems like this can not be solved without compromise, workaround or major change. :/
One useful compromise might be to only support cases where the the asset proxy knows by itself what the correct asset id is. Either because taker told the proxy in advance, or because it can be computed during the fill. I'd need to think further about what this allows.
Superseded by #75
Summary
Allow the trading of assets based on their properties, rather than their exact identifier.
Motivation
Creating liquidity for NFT's is a challenge as the AssetProxy requires the identifier in its encoding. Traders currently create orders for specific NFTs,
1 DAI for Axie #123
. This ZEIP makes it possible to create general standing orders, such as1 DAI for an Axie
and100 Dai for 100 Axies
. It is also possible to createOR
orders such as1 DAI for an Axie or Etheremon
.Property Based Orders allow the trader to specify the exact properties of the asset they require, such assets may not even exist yet. Having a number of these orders in an order allows a base line price discovery mechanism.
Specification
Implementation
A simple way to achieve the challenge of taker supplied data is by using the
matchOrders
function in Exchange. This receives 2 orders as input, allowing the taker to supply parameters in the second order.Challenges
It is not currently possible for a taker to supply additional data using fillOrder and the batch variants. The taker does supply the signature, though adding additional encoding here is not ideal.
The order may be for a number of assets, i.e
100 DAI for 100 Axies
, the design should allow the taker to supply an arbitrary number of assets (via the MultiAssetProxy). This will need to be enforced by the maker predicate. As such it will need to handle MultiAssetProxy encoded data.