@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",
"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
view
returns (uint256[] memory makerTokenAmounts)
returns (IMooniswap pool, uint256[] memory makerTokenAmounts)
{
_assertValidPair(makerToken, takerToken);
uint256 numSamples = takerTokenAmounts.length;
makerTokenAmounts = new uint256[](numSamples);
address _takerToken = takerToken == _getWethAddress() ? address(0) : takerToken;
address _makerToken = makerToken == _getWethAddress() ? address(0) : makerToken;
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)
IMooniswap pool = IMooniswap(
IMooniswapRegistry(_getMooniswapAddress()).pools(_takerToken, _makerToken)
pool = IMooniswap(
IMooniswapRegistry(_getMooniswapAddress()).pools(mooniswapTakerToken, mooniswapMakerToken)
);
// If there is no pool then return early
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++) {
// If the pool balance is smaller than the sell amount
// don't sample to avoid multiplication overflow in buys
if (poolBalance < takerTokenAmounts[i]) {
break;
}
(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));
}
uint256 buyAmount = sampleSingleSellFromMooniswapPool(
pool,
mooniswapTakerToken,
mooniswapMakerToken,
takerTokenAmounts[i]
);
// Exit early if the amount is too high for the source to serve
if (buyAmount == 0) {
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.
/// @param takerToken Address of the taker token (what to sell).
/// @param makerToken Address of the maker token (what to buy).
@@ -105,12 +124,28 @@ contract MooniswapSampler is
)
public
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({
makerTokenData: abi.encode(makerToken),
takerTokenData: abi.encode(takerToken),
makerTokenData: abi.encode(mooniswapMakerToken, pool),
takerTokenData: abi.encode(mooniswapTakerToken, pool),
getSellQuoteCallback: _sampleSellForApproximateBuyFromMooniswap
}),
makerTokenAmounts
@@ -126,15 +161,16 @@ contract MooniswapSampler is
view
returns (uint256 buyAmount)
{
(address takerToken) =
abi.decode(takerTokenData, (address));
(address makerToken) =
(address mooniswapTakerToken, IMooniswap pool) =
abi.decode(takerTokenData, (address, IMooniswap));
(address mooniswapMakerToken) =
abi.decode(makerTokenData, (address));
(bool success, bytes memory resultData) =
address(this).staticcall(abi.encodeWithSelector(
this.sampleSellsFromMooniswap.selector,
takerToken,
makerToken,
this.sampleSingleSellFromMooniswapPool.selector,
pool,
mooniswapTakerToken,
mooniswapMakerToken,
_toSingleValueArray(sellAmount)
));
if (!success) {

View File

@@ -29,6 +29,7 @@ import {
Fill,
KyberFillData,
LiquidityProviderFillData,
MooniswapFillData,
MultiBridgeFillData,
MultiHopFillData,
NativeCollapsedFill,
@@ -304,6 +305,14 @@ function createBridgeOrder(
createKyberBridgeData(takerToken, kyberFillData.hint),
);
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:
makerAssetData = assetDataUtils.encodeERC20BridgeAssetData(
makerToken,
@@ -407,6 +416,11 @@ function createKyberBridgeData(fromTokenAddress: string, hint: string): string {
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(
curveAddress: string,
exchangeFunctionSelector: string,

View File

@@ -23,6 +23,7 @@ import {
HopInfo,
KyberFillData,
LiquidityProviderFillData,
MooniswapFillData,
MultiBridgeFillData,
MultiHopFillData,
SourceQuoteOperation,
@@ -446,6 +447,14 @@ export class SamplerOperations {
contract: this._samplerContract,
function: this._samplerContract.sampleSellsFromMooniswap,
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,
function: this._samplerContract.sampleBuysFromMooniswap,
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;
}
export interface MooniswapFillData extends FillData {
poolAddress: string;
}
export interface Quote<TFillData = FillData> {
amount: BigNumber;
fillData?: TFillData;