Merge pull request #2491 from 0xProject/fix/instant/support-erc721
[FIX] Instant + Asset-swapper support for ERC721
This commit is contained in:
commit
cded58c30d
@ -1,4 +1,17 @@
|
||||
[
|
||||
{
|
||||
"version": "4.4.0",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Add support for ERC721 assets",
|
||||
"pr": 2491
|
||||
},
|
||||
{
|
||||
"note": "Add destroy for gas heartbeat",
|
||||
"pr": 2492
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "4.3.2",
|
||||
"changes": [
|
||||
|
@ -234,6 +234,7 @@ export enum SwapQuoterError {
|
||||
InsufficientAssetLiquidity = 'INSUFFICIENT_ASSET_LIQUIDITY',
|
||||
AssetUnavailable = 'ASSET_UNAVAILABLE',
|
||||
NoGasPriceProvidedOrEstimated = 'NO_GAS_PRICE_PROVIDED_OR_ESTIMATED',
|
||||
AssetDataUnsupported = 'ASSET_DATA_UNSUPPORTED',
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1,5 +1,6 @@
|
||||
import { ContractAddresses } from '@0x/contract-addresses';
|
||||
import { assetDataUtils, generatePseudoRandomSalt } from '@0x/order-utils';
|
||||
import { SignedOrder } from '@0x/types';
|
||||
import { AbiEncoder, BigNumber } from '@0x/utils';
|
||||
|
||||
import { constants } from '../../constants';
|
||||
@ -20,6 +21,22 @@ const { INFINITE_TIMESTAMP_SEC, WALLET_SIGNATURE } = marketOperationUtilConstant
|
||||
export class CreateOrderUtils {
|
||||
private readonly _contractAddress: ContractAddresses;
|
||||
|
||||
// utility function for asset-swapper to ignore market operation utils for specific asset types
|
||||
public static convertNativeOrderToFullyFillableOptimizedOrders(order: SignedOrder): OptimizedMarketOrder {
|
||||
return {
|
||||
...order,
|
||||
fillableMakerAssetAmount: order.makerAssetAmount,
|
||||
fillableTakerAssetAmount: order.takerAssetAmount,
|
||||
fillableTakerFeeAmount: order.takerFee,
|
||||
fill: {
|
||||
source: ERC20BridgeSource.Native,
|
||||
totalMakerAssetAmount: order.makerAssetAmount,
|
||||
totalTakerAssetAmount: order.takerAssetAmount,
|
||||
subFills: [],
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
constructor(contractAddress: ContractAddresses) {
|
||||
this._contractAddress = contractAddress;
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { orderCalculationUtils } from '@0x/order-utils';
|
||||
import { SignedOrder } from '@0x/types';
|
||||
import { assetDataUtils, orderCalculationUtils } from '@0x/order-utils';
|
||||
import { AssetProxyId, SignedOrder } from '@0x/types';
|
||||
import { BigNumber } from '@0x/utils';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
@ -14,10 +14,12 @@ import {
|
||||
SwapQuoteBase,
|
||||
SwapQuoteInfo,
|
||||
SwapQuoteOrdersBreakdown,
|
||||
SwapQuoterError,
|
||||
} from '../types';
|
||||
|
||||
import { fillableAmountsUtils } from './fillable_amounts_utils';
|
||||
import { MarketOperationUtils } from './market_operation_utils';
|
||||
import { CreateOrderUtils } from './market_operation_utils/create_order';
|
||||
import { ERC20BridgeSource, OptimizedMarketOrder } from './market_operation_utils/types';
|
||||
import { ProtocolFeeUtils } from './protocol_fee_utils';
|
||||
import { utils } from './utils';
|
||||
@ -126,6 +128,10 @@ export class SwapQuoteCalculator {
|
||||
operation: MarketOperation,
|
||||
opts: CalculateSwapQuoteOpts,
|
||||
): Promise<SwapQuote> {
|
||||
// checks if maker asset is ERC721 or ERC20 and taker asset is ERC20
|
||||
if (!utils.isSupportedAssetDataInOrders(prunedOrders)) {
|
||||
throw Error(SwapQuoterError.AssetDataUnsupported);
|
||||
}
|
||||
// since prunedOrders do not have fillState, we will add a buffer of fillable orders to consider that some native are orders are partially filled
|
||||
|
||||
const slippageBufferAmount = assetFillAmount.multipliedBy(slippagePercentage).integerValue();
|
||||
@ -137,6 +143,17 @@ export class SwapQuoteCalculator {
|
||||
...opts,
|
||||
fees: _.mapValues(opts.fees, (v, k) => v.times(gasPrice)),
|
||||
};
|
||||
|
||||
const firstOrderMakerAssetData = !!prunedOrders[0]
|
||||
? assetDataUtils.decodeAssetDataOrThrow(prunedOrders[0].makerAssetData)
|
||||
: { assetProxyId: '' };
|
||||
|
||||
if (firstOrderMakerAssetData.assetProxyId === AssetProxyId.ERC721) {
|
||||
// HACK: to conform ERC721 orders to the output of market operation utils, assumes complete fillable
|
||||
resultOrders = prunedOrders.map(o =>
|
||||
CreateOrderUtils.convertNativeOrderToFullyFillableOptimizedOrders(o),
|
||||
);
|
||||
} else {
|
||||
if (operation === MarketOperation.Buy) {
|
||||
resultOrders = await this._marketOperationUtils.getMarketBuyOrdersAsync(
|
||||
prunedOrders,
|
||||
@ -151,6 +168,7 @@ export class SwapQuoteCalculator {
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// assetData information for the result
|
||||
const { makerAssetData, takerAssetData } = prunedOrders[0];
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { assetDataUtils } from '@0x/order-utils';
|
||||
import { AssetData, ERC20AssetData, ERC20BridgeAssetData, Order } from '@0x/types';
|
||||
import { AssetData, AssetProxyId, ERC20AssetData, ERC20BridgeAssetData, Order, SignedOrder } from '@0x/types';
|
||||
import { BigNumber, NULL_BYTES } from '@0x/utils';
|
||||
import { Web3Wrapper } from '@0x/web3-wrapper';
|
||||
|
||||
@ -7,6 +7,21 @@ import { constants } from '../constants';
|
||||
|
||||
// tslint:disable:no-unnecessary-type-assertion
|
||||
export const utils = {
|
||||
isSupportedAssetDataInOrders(orders: SignedOrder[]): boolean {
|
||||
const firstOrderMakerAssetData = !!orders[0]
|
||||
? assetDataUtils.decodeAssetDataOrThrow(orders[0].makerAssetData)
|
||||
: { assetProxyId: '' };
|
||||
return orders.every(o => {
|
||||
const takerAssetData = assetDataUtils.decodeAssetDataOrThrow(o.takerAssetData);
|
||||
const makerAssetData = assetDataUtils.decodeAssetDataOrThrow(o.makerAssetData);
|
||||
return (
|
||||
(makerAssetData.assetProxyId === AssetProxyId.ERC20 ||
|
||||
makerAssetData.assetProxyId === AssetProxyId.ERC721) &&
|
||||
takerAssetData.assetProxyId === AssetProxyId.ERC20 &&
|
||||
firstOrderMakerAssetData.assetProxyId === makerAssetData.assetProxyId
|
||||
); // checks that all native order maker assets are of the same type
|
||||
});
|
||||
},
|
||||
numberPercentageToEtherTokenAmountPercentage(percentage: number): BigNumber {
|
||||
return Web3Wrapper.toBaseUnitAmount(constants.ONE_AMOUNT, constants.ETHER_TOKEN_DECIMALS).multipliedBy(
|
||||
percentage,
|
||||
|
@ -1,4 +1,17 @@
|
||||
[
|
||||
{
|
||||
"version": "4.2.0",
|
||||
"changes": [
|
||||
{
|
||||
"note": "Clean up heartbeat functions on close",
|
||||
"pr": 2492
|
||||
},
|
||||
{
|
||||
"note": "Fix ERC721 asset support",
|
||||
"pr": 2491
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "4.1.0",
|
||||
"changes": [
|
||||
|
@ -72,7 +72,9 @@ export class InstantHeading extends React.PureComponent<InstantHeadingProps, {}>
|
||||
overflow="hidden"
|
||||
borderRadius="50%"
|
||||
>
|
||||
<Flex justify="center" align="center" height="100%">
|
||||
<Image src={asset.metaData.imageUrl} height="100%" objectFit="cover" />
|
||||
</Flex>
|
||||
</Container>
|
||||
</Flex>
|
||||
</Container>
|
||||
|
Loading…
x
Reference in New Issue
Block a user