@0x/asset-swapper: Return Mooniswap pool in sampler and encode it in bridge data

This commit is contained in:
Lawrence Forman
2020-09-02 17:42:03 -04:00
parent 705f46717f
commit 4049143630
5 changed files with 110 additions and 35 deletions

View File

@@ -97,6 +97,10 @@
{ {
"note": "Set `rfqtTakerAddress` to null in EP consumer", "note": "Set `rfqtTakerAddress` to null in EP consumer",
"pr": 2692 "pr": 2692
},
{
"note": "Return Mooniswap pool in sampler and encode it in bridge data",
"pr": 2692
} }
] ]
}, },

View File

@@ -46,44 +46,31 @@ contract MooniswapSampler is
) )
public public
view view
returns (uint256[] memory makerTokenAmounts) returns (IMooniswap pool, uint256[] memory makerTokenAmounts)
{ {
_assertValidPair(makerToken, takerToken); _assertValidPair(makerToken, takerToken);
uint256 numSamples = takerTokenAmounts.length; uint256 numSamples = takerTokenAmounts.length;
makerTokenAmounts = new uint256[](numSamples); makerTokenAmounts = new uint256[](numSamples);
address _takerToken = takerToken == _getWethAddress() ? address(0) : takerToken; address mooniswapTakerToken = takerToken == _getWethAddress() ? address(0) : takerToken;
address _makerToken = makerToken == _getWethAddress() ? address(0) : makerToken; address mooniswapMakerToken = makerToken == _getWethAddress() ? address(0) : makerToken;
// Find the pool for the pair, ETH is represented // Find the pool for the pair, ETH is represented
// as address(0) // as address(0)
IMooniswap pool = IMooniswap( pool = IMooniswap(
IMooniswapRegistry(_getMooniswapAddress()).pools(_takerToken, _makerToken) IMooniswapRegistry(_getMooniswapAddress()).pools(mooniswapTakerToken, mooniswapMakerToken)
); );
// If there is no pool then return early // If there is no pool then return early
if (address(pool) == address(0)) { if (address(pool) == address(0)) {
return makerTokenAmounts; return (pool, makerTokenAmounts);
} }
uint256 poolBalance = _takerToken == address(0) ? address(pool).balance : IERC20Token(_takerToken).balanceOf(address(pool));
for (uint256 i = 0; i < numSamples; i++) { for (uint256 i = 0; i < numSamples; i++) {
// If the pool balance is smaller than the sell amount uint256 buyAmount = sampleSingleSellFromMooniswapPool(
// don't sample to avoid multiplication overflow in buys pool,
if (poolBalance < takerTokenAmounts[i]) { mooniswapTakerToken,
break; mooniswapMakerToken,
} takerTokenAmounts[i]
(bool didSucceed, bytes memory resultData) = );
address(pool).staticcall.gas(MOONISWAP_CALL_GAS)(
abi.encodeWithSelector(
IMooniswap(0).getReturn.selector,
_takerToken,
_makerToken,
takerTokenAmounts[i]
));
uint256 buyAmount = 0;
if (didSucceed) {
buyAmount = abi.decode(resultData, (uint256));
}
// Exit early if the amount is too high for the source to serve // Exit early if the amount is too high for the source to serve
if (buyAmount == 0) { if (buyAmount == 0) {
break; break;
@@ -92,6 +79,38 @@ contract MooniswapSampler is
} }
} }
function sampleSingleSellFromMooniswapPool(
IMooniswap pool,
address mooniswapTakerToken,
address mooniswapMakerToken,
uint256 takerTokenAmount
)
public
view
returns (uint256 makerTokenAmount)
{
uint256 poolBalance = mooniswapTakerToken == address(0)
? address(pool).balance
: IERC20Token(mooniswapTakerToken).balanceOf(address(pool));
// If the pool balance is smaller than the sell amount
// don't sample to avoid multiplication overflow in buys
if (poolBalance < takerTokenAmount) {
return makerTokenAmount;
}
(bool didSucceed, bytes memory resultData) =
address(pool).staticcall.gas(MOONISWAP_CALL_GAS)(
abi.encodeWithSelector(
IMooniswap(0).getReturn.selector,
mooniswapTakerToken,
mooniswapMakerToken,
takerTokenAmount
));
if (didSucceed) {
makerTokenAmount = abi.decode(resultData, (uint256));
}
}
/// @dev Sample buy quotes from Mooniswap. /// @dev Sample buy quotes from Mooniswap.
/// @param takerToken Address of the taker token (what to sell). /// @param takerToken Address of the taker token (what to sell).
/// @param makerToken Address of the maker token (what to buy). /// @param makerToken Address of the maker token (what to buy).
@@ -105,12 +124,28 @@ contract MooniswapSampler is
) )
public public
view view
returns (uint256[] memory takerTokenAmounts) returns (IMooniswap pool, uint256[] memory takerTokenAmounts)
{ {
return _sampleApproximateBuys( _assertValidPair(makerToken, takerToken);
uint256 numSamples = takerTokenAmounts.length;
makerTokenAmounts = new uint256[](numSamples);
address mooniswapTakerToken = takerToken == _getWethAddress() ? address(0) : takerToken;
address mooniswapMakerToken = makerToken == _getWethAddress() ? address(0) : makerToken;
// Find the pool for the pair, ETH is represented
// as address(0)
pool = IMooniswap(
IMooniswapRegistry(_getMooniswapAddress()).pools(mooniswapTakerToken, mooniswapMakerToken)
);
// If there is no pool then return early
if (address(pool) == address(0)) {
return (pool, takerTokenAmounts);
}
takerTokenAmounts = _sampleApproximateBuys(
ApproximateBuyQuoteOpts({ ApproximateBuyQuoteOpts({
makerTokenData: abi.encode(makerToken), makerTokenData: abi.encode(mooniswapMakerToken, pool),
takerTokenData: abi.encode(takerToken), takerTokenData: abi.encode(mooniswapTakerToken, pool),
getSellQuoteCallback: _sampleSellForApproximateBuyFromMooniswap getSellQuoteCallback: _sampleSellForApproximateBuyFromMooniswap
}), }),
makerTokenAmounts makerTokenAmounts
@@ -126,15 +161,16 @@ contract MooniswapSampler is
view view
returns (uint256 buyAmount) returns (uint256 buyAmount)
{ {
(address takerToken) = (address mooniswapTakerToken, IMooniswap pool) =
abi.decode(takerTokenData, (address)); abi.decode(takerTokenData, (address, IMooniswap));
(address makerToken) = (address mooniswapMakerToken) =
abi.decode(makerTokenData, (address)); abi.decode(makerTokenData, (address));
(bool success, bytes memory resultData) = (bool success, bytes memory resultData) =
address(this).staticcall(abi.encodeWithSelector( address(this).staticcall(abi.encodeWithSelector(
this.sampleSellsFromMooniswap.selector, this.sampleSingleSellFromMooniswapPool.selector,
takerToken, pool,
makerToken, mooniswapTakerToken,
mooniswapMakerToken,
_toSingleValueArray(sellAmount) _toSingleValueArray(sellAmount)
)); ));
if (!success) { if (!success) {

View File

@@ -29,6 +29,7 @@ import {
Fill, Fill,
KyberFillData, KyberFillData,
LiquidityProviderFillData, LiquidityProviderFillData,
MooniswapFillData,
MultiBridgeFillData, MultiBridgeFillData,
MultiHopFillData, MultiHopFillData,
NativeCollapsedFill, NativeCollapsedFill,
@@ -304,6 +305,14 @@ function createBridgeOrder(
createKyberBridgeData(takerToken, kyberFillData.hint), createKyberBridgeData(takerToken, kyberFillData.hint),
); );
break; break;
case ERC20BridgeSource.Mooniswap:
const mooniswapFillData = (fill as CollapsedFill<MooniswapFillData>).fillData!; // tslint:disable-line:no-non-null-assertion
makerAssetData = assetDataUtils.encodeERC20BridgeAssetData(
makerToken,
bridgeAddress,
createMooniswapBridgeData(takerToken, mooniswapFillData.poolAddress),
);
break;
default: default:
makerAssetData = assetDataUtils.encodeERC20BridgeAssetData( makerAssetData = assetDataUtils.encodeERC20BridgeAssetData(
makerToken, makerToken,
@@ -407,6 +416,11 @@ function createKyberBridgeData(fromTokenAddress: string, hint: string): string {
return encoder.encode({ fromTokenAddress, hint }); return encoder.encode({ fromTokenAddress, hint });
} }
function createMooniswapBridgeData(takerToken: string, poolAddress: string): string {
const encoder = AbiEncoder.create([{ name: 'takerToken', type: 'address' }, { name: 'pool', type: 'address' }]);
return encoder.encode({ takerToken, poolAddress });
}
function createCurveBridgeData( function createCurveBridgeData(
curveAddress: string, curveAddress: string,
exchangeFunctionSelector: string, exchangeFunctionSelector: string,

View File

@@ -23,6 +23,7 @@ import {
HopInfo, HopInfo,
KyberFillData, KyberFillData,
LiquidityProviderFillData, LiquidityProviderFillData,
MooniswapFillData,
MultiBridgeFillData, MultiBridgeFillData,
MultiHopFillData, MultiHopFillData,
SourceQuoteOperation, SourceQuoteOperation,
@@ -446,6 +447,14 @@ export class SamplerOperations {
contract: this._samplerContract, contract: this._samplerContract,
function: this._samplerContract.sampleSellsFromMooniswap, function: this._samplerContract.sampleSellsFromMooniswap,
params: [takerToken, makerToken, takerFillAmounts], params: [takerToken, makerToken, takerFillAmounts],
callback: (callResults: string, fillData: MooniswapFillData): BigNumber[] => {
const [poolAddress, samples] = this._samplerContract.getABIDecodedReturnData<[string, BigNumber[]]>(
'sampleSellsFromMooniswap',
callResults,
);
fillData.poolAddress = poolAddress;
return samples;
},
}); });
} }
@@ -459,6 +468,14 @@ export class SamplerOperations {
contract: this._samplerContract, contract: this._samplerContract,
function: this._samplerContract.sampleBuysFromMooniswap, function: this._samplerContract.sampleBuysFromMooniswap,
params: [takerToken, makerToken, makerFillAmounts], params: [takerToken, makerToken, makerFillAmounts],
callback: (callResults: string, fillData: MooniswapFillData): BigNumber[] => {
const [poolAddress, samples] = this._samplerContract.getABIDecodedReturnData<[string, BigNumber[]]>(
'sampleBuysFromMooniswap',
callResults,
);
fillData.poolAddress = poolAddress;
return samples;
},
}); });
} }

View File

@@ -113,6 +113,10 @@ export interface KyberFillData extends FillData {
reserveId: string; reserveId: string;
} }
export interface MooniswapFillData extends FillData {
poolAddress: string;
}
export interface Quote<TFillData = FillData> { export interface Quote<TFillData = FillData> {
amount: BigNumber; amount: BigNumber;
fillData?: TFillData; fillData?: TFillData;