-
Notifications
You must be signed in to change notification settings - Fork 465
[asset-buyer] Create new AssetBuyer class #1037
Conversation
*/ | ||
async getForwarderHelperForMakerAssetDataAsync( | ||
makerAssetData: string, | ||
takerAddress: string, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
remove this since we do not actually need any on chain info for the taker
const [makerAssetOrderbook, zrxOrderbook] = await Promise.all( | ||
_.map(orderbookRequests, request => sraClient.getOrderbookAsync(request, requestOpts)), | ||
); | ||
// validate orders and find remaining fillable from on chain state or sra api |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we potentially want to filter out orders where the taker is not null address (i.e. not an open order)
} | ||
providerEngine.start(); | ||
// create contract wrappers given provider and networkId | ||
const contractWrappers = new ContractWrappers(providerEngine, { networkId }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we might be able to extract out the contractWrappers creation into a different factory to make this function a bit shorter, we will also want to use the wrappers to validate orders that don't come from an SRA endpoint
{ baseAssetData: zrxTokenAssetData, quoteAssetData: etherTokenAssetData }, | ||
]; | ||
const requestOpts = { networkId }; | ||
// TODO: try catch these requests and throw a more domain specific error |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
STANDARD_RELAYER_API_ERROR
// if we do have an rpc url, get on-chain orders and traders info via the OrderValidatorWrapper | ||
const ordersFromSra = _.map(makerAssetOrderbook.asks.records, apiOrder => apiOrder.order); | ||
const feeOrdersFromSra = _.map(zrxOrderbook.asks.records, apiOrder => apiOrder.order); | ||
// TODO: try catch these requests and throw a more domain specific error |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ETHEREUM_NODE_RPC_ERROR
// TODO: try catch these requests and throw a more domain specific error | ||
const [makerAssetOrdersAndTradersInfo, feeOrdersAndTradersInfo] = await Promise.all( | ||
_.map([ordersFromSra, feeOrdersFromSra], ordersToBeValidated => { | ||
const takerAddresses = _.map(ordersToBeValidated, () => takerAddress); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
change this to NULL_ADDRESS in conjunction w/ removing takerAddress from the function args
): OrdersAndRemainingFillableMakerAssetAmounts { | ||
const result = _.reduce( | ||
apiOrders, | ||
(acc, apiOrder, index) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
index is not used here
if (orderUtils.isOrderExpired(order)) { | ||
return acc; | ||
} | ||
// calculate remainingFillableMakerAssetAmount from api metadata |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
add comment about trying to grab remaining taker amount from SRA metadata, else, assume order is completely fillable
const { orders, remainingFillableMakerAssetAmounts } = acc; | ||
// get corresponding on-chain state for the order | ||
const { orderInfo, traderInfo } = ordersAndTradersInfo[index]; | ||
// if the order IS NOT fillable, do not add anything and continue iterating |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"do not add anything to the accumulations"
}, | ||
calculateRemainingMakerAssetAmount(order: SignedOrder, remainingTakerAssetAmount: BigNumber): BigNumber { | ||
const result = remainingTakerAssetAmount.eq(0) | ||
? new BigNumber(0) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
constants.ZERO_AMOUNT
|
||
export const forwarderHelperFactory = { | ||
/** | ||
* Given an array of orders and an array of feeOrders | ||
* Given an array of orders and an array of feeOrders, get a ForwarderHelper |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add checks here for orders all having the same makerAsset and takerAsset
118a8be
to
44aa369
Compare
44aa369
to
d57619b
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Need to add StandardRelayerApiAssetBuyerManager
const SLIPPAGE_PERCENTAGE = 0.2; // 20% slippage protection, possibly move this into request interface | ||
const DEFAULT_ORDER_REFRESH_INTERVAL_MS = 10000; // 10 seconds | ||
const DEFAULT_FEE_PERCENTAGE = 0; | ||
const ETHER_TOKEN_DECIMALS = 18; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Move to constants file
* Defaults to 10000ms (10s). | ||
* @return An instance of AssetBuyer | ||
*/ | ||
constructor( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we want to have a factory method for providing your own orders but not your own fee orders (and passing in an sraUrl instead?)
packages/asset-buyer/src/types.ts
Outdated
feeOrders: SignedOrderWithRemainingFillableMakerAssetAmount[]; | ||
remainingFillableMakerAssetAmounts: BigNumber[]; | ||
remainingFillableFeeAmounts: BigNumber[]; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
do we need remainingFillableMakerAssetAmounts
and remainingFillableFeeAmounts
now that we have SignedOrderWithRemainingFillableMakerAssetAmount
?
Seems like we should choose one format over the other.
orders: SignedOrderWithRemainingFillableMakerAssetAmount[], | ||
): SignedOrderWithRemainingFillableMakerAssetAmount[] { | ||
const result = _.filter(orders, order => { | ||
return orderUtils.isOpenOrder(order) && orderUtils.isOrderExpired(order); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should probably be!orderUtils.isOrderExpired
packages/asset-buyer/README.md
Outdated
|
||
Provides convenience objects to help work with the Forwarder Contract | ||
Convenience package for buying assets |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you please provide a more elaborate description, this is too vague.
private _lastRefreshTimeIfExists?: number; | ||
private _currentOrdersAndFillableAmountsIfExists?: AssetBuyerOrdersAndFillableAmounts; | ||
/** | ||
* Instantiates a new AssetBuyer instance |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Improve this comment and the subsequent method comment, they are identical but these methods are slightly different.
return assetBuyer; | ||
} | ||
/** | ||
* Instantiates a new AssetBuyer instance |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ditto above.
orderRefreshIntervalMs, | ||
); | ||
return assetBuyer; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Rather then have the above methods be static methods on AssetBuyer
, I think it would be clearer to have then as part of a AssetBuyerFactory
module. Thoughts?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm personally a fan of static init methods on the class itself but open to changing it if we've established a strong convention of using factories.
} | ||
/** | ||
* Get a BuyQuote containing all information relevant to fulfilling a buy. | ||
* Pass the BuyQuote to executeBuyQuoteAsync to execute the buy. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For clarity: You can then pass the `BuyQuote` to `executeBuyQuoteAsync` to execute the buy.
orderValidator?: OrderValidatorWrapper, | ||
): Promise<AssetBuyerOrdersAndFillableAmounts> { | ||
// drop orders that are expired or not open | ||
const filteredTargetOrders = filterOutExpiredAndNonOpenOrders(targetOrderFetcherResponse.orders); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there an "expiryBuffer" that users can configure? They might want to be overly cautious, since attempting to fill and expired order will result in them losing gas costs. Since blocks are mined every ~12 seconds, it's hard to predict if an order with 3sec left has a high chance of making it into the next block. Chances are slim but not impossible.
let unsortedFeeOrders = filteredFeeOrders; | ||
// if an orderValidator is provided, use on chain information to calculate remaining fillable makerAsset amounts | ||
if (!_.isUndefined(orderValidator)) { | ||
// TODO: critical |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add author.
// if an orderValidator is provided, use on chain information to calculate remaining fillable makerAsset amounts | ||
if (!_.isUndefined(orderValidator)) { | ||
// TODO: critical | ||
// try catch these requests and throw a more domain specific error |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you elaborate on this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the comment means that we should be catching the various potential errors from the smart contract wrappers and returning more useful/asset-buyer specific error messages to the users of asset-buyer. However, I reprioritized this to "improvement"
(acc, orderWithAmount) => { | ||
const { orders, remainingFillableMakerAssetAmounts } = acc; | ||
const { remainingFillableMakerAssetAmount, ...order } = orderWithAmount; | ||
// if we are still missing a remainingFillableMakerAssetAmount, assume the order is completely fillable |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In which edge-cases would the remainingFillableMakerAssetAmount
still be missing at this point?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In practice it wouldn't be, but the type system wants this check since the type can be undefined.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hm, then this comment feels misleading. I'm not a big fan of _.reduce
, you could also write this as a simply _.each
loop.
"version": "1.1.0", | ||
"changes": [ | ||
{ | ||
"note": "Add ObjectMap type", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🙏
…into feature/forwarder-helper/sra-and-rpc
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please address the remaining changes, then LGTM
packages/asset-buyer/README.md
Outdated
## @0xproject/asset-buyer | ||
|
||
Convenience package for buying assets represented on the Ethereum blockchain using 0x. In its simplest form, the package helps in the usage of the [0x forwarder contract](https://github.com/0xProject/0x-protocol-specification/blob/master/v2/forwarder-specification.md), which allows users to execute Wrapped Ether based 0x orders without having to set allowances, wrap Ether or buy ZRX, meaning they can buy tokens with Ether alone. Given some liquidity (0x signed orders), it helps estimate the Ether cost of buying a certain asset (giving a range) and then buying that asset. | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's link Wrapped Ether
to https://weth.io/
packages/asset-buyer/README.md
Outdated
|
||
In its more advanced and useful form, it integrates with the [Standard Relayer API](https://github.com/0xProject/standard-relayer-api) and takes care of sourcing liquidity for you given an SRA compliant endpoint. The final result is a library that tells you what assets are available, provides an Ether based quote for any asset desired, and allows you to buy that asset using Ether alone. | ||
|
||
### Read the [Documentation](https://0xproject.com/docs/asset-buyer). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will there really be a documentation page for this package? If "eventually" is the answer, let's remove this line for now.
packages/asset-buyer/package.json
Outdated
"@0xproject/typescript-typings": "^2.0.1", | ||
"@0xproject/utils": "^1.0.9", | ||
"@types/node": "*", | ||
"@0xproject/assert": "^1.0.8", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There has been a publish in the mean-time. This should be ^1.0.9
and others are probably also out-of-date.
…into feature/forwarder-helper/sra-and-rpc
Ok we have determined the test-publish job has been failing because of memory issues. So merging. |
Description
AssetBuyer
classTesting instructions
TBD
Types of changes
Checklist:
[WIP]
if necessary.[sol-cov] Fixed bug
.