parent
6f8971cc42
commit
76987c8db1
@ -1,4 +1,13 @@
|
|||||||
[
|
[
|
||||||
|
{
|
||||||
|
"version": "16.19.1",
|
||||||
|
"changes": [
|
||||||
|
{
|
||||||
|
"note": "Fix LiquidityProvider fallback",
|
||||||
|
"pr": 272
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"version": "16.19.0",
|
"version": "16.19.0",
|
||||||
"changes": [
|
"changes": [
|
||||||
|
@ -78,6 +78,11 @@ export class Path {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a fallback path to the current path
|
||||||
|
* Fallback must contain exclusive fills that are
|
||||||
|
* not present in this path
|
||||||
|
*/
|
||||||
public addFallback(fallback: Path): this {
|
public addFallback(fallback: Path): this {
|
||||||
// If the last fill is Native and penultimate is not, then the intention was to partial fill
|
// If the last fill is Native and penultimate is not, then the intention was to partial fill
|
||||||
// In this case we drop it entirely as we can't handle a failure at the end and we don't
|
// In this case we drop it entirely as we can't handle a failure at the end and we don't
|
||||||
@ -93,7 +98,16 @@ export class Path {
|
|||||||
// an additional protocol fee. I.e [Uniswap,Native,Kyber] becomes [Native,Uniswap,Kyber]
|
// an additional protocol fee. I.e [Uniswap,Native,Kyber] becomes [Native,Uniswap,Kyber]
|
||||||
// In the previous step we dropped any hanging Native partial fills, as to not fully fill
|
// In the previous step we dropped any hanging Native partial fills, as to not fully fill
|
||||||
const nativeFills = this.fills.filter(f => f.source === ERC20BridgeSource.Native);
|
const nativeFills = this.fills.filter(f => f.source === ERC20BridgeSource.Native);
|
||||||
this.fills = [...nativeFills.filter(f => f !== lastNativeFillIfExists), ...fallback.fills];
|
const otherFills = this.fills.filter(f => f.source !== ERC20BridgeSource.Native);
|
||||||
|
const otherSourcePathIds = otherFills.map(f => f.sourcePathId);
|
||||||
|
this.fills = [
|
||||||
|
// Append all of the native fills first
|
||||||
|
...nativeFills.filter(f => f !== lastNativeFillIfExists),
|
||||||
|
// Add the other fills that are not native in the optimal path
|
||||||
|
...otherFills,
|
||||||
|
// Add the fallbacks to the end that aren't already included
|
||||||
|
...fallback.fills.filter(f => !otherSourcePathIds.includes(f.sourcePathId)),
|
||||||
|
];
|
||||||
// Recompute the source flags
|
// Recompute the source flags
|
||||||
this.sourceFlags = this.fills.reduce((flags, fill) => flags | fill.flags, BigInt(0));
|
this.sourceFlags = this.fills.reduce((flags, fill) => flags | fill.flags, BigInt(0));
|
||||||
return this;
|
return this;
|
||||||
|
86
packages/asset-swapper/test/path_test.ts
Normal file
86
packages/asset-swapper/test/path_test.ts
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
import { expect } from '@0x/contracts-test-utils';
|
||||||
|
import { BigNumber } from '@0x/utils';
|
||||||
|
|
||||||
|
import { MarketOperation } from '../src/types';
|
||||||
|
import { Path } from '../src/utils/market_operation_utils/path';
|
||||||
|
import { ERC20BridgeSource, Fill } from '../src/utils/market_operation_utils/types';
|
||||||
|
|
||||||
|
const createFill = (
|
||||||
|
source: ERC20BridgeSource,
|
||||||
|
input: BigNumber = new BigNumber(100),
|
||||||
|
output: BigNumber = new BigNumber(100),
|
||||||
|
): Fill =>
|
||||||
|
// tslint:disable-next-line: no-object-literal-type-assertion
|
||||||
|
({
|
||||||
|
source,
|
||||||
|
input,
|
||||||
|
output,
|
||||||
|
adjustedOutput: output,
|
||||||
|
flags: BigInt(0),
|
||||||
|
sourcePathId: source,
|
||||||
|
} as Fill);
|
||||||
|
|
||||||
|
describe('Path', () => {
|
||||||
|
it('Adds a fallback', () => {
|
||||||
|
const targetInput = new BigNumber(100);
|
||||||
|
const path = Path.create(
|
||||||
|
MarketOperation.Sell,
|
||||||
|
[createFill(ERC20BridgeSource.Native), createFill(ERC20BridgeSource.Native)],
|
||||||
|
targetInput,
|
||||||
|
);
|
||||||
|
const fallback = Path.create(MarketOperation.Sell, [createFill(ERC20BridgeSource.Uniswap)], targetInput);
|
||||||
|
path.addFallback(fallback);
|
||||||
|
const sources = path.fills.map(f => f.source);
|
||||||
|
expect(sources).to.deep.eq([ERC20BridgeSource.Native, ERC20BridgeSource.Native, ERC20BridgeSource.Uniswap]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Adds a fallback with LiquidityProvider', () => {
|
||||||
|
const targetInput = new BigNumber(100);
|
||||||
|
const path = Path.create(
|
||||||
|
MarketOperation.Sell,
|
||||||
|
[createFill(ERC20BridgeSource.Native), createFill(ERC20BridgeSource.LiquidityProvider)],
|
||||||
|
targetInput,
|
||||||
|
);
|
||||||
|
const fallback = Path.create(MarketOperation.Sell, [createFill(ERC20BridgeSource.Uniswap)], targetInput);
|
||||||
|
path.addFallback(fallback);
|
||||||
|
const sources = path.fills.map(f => f.source);
|
||||||
|
expect(sources).to.deep.eq([
|
||||||
|
ERC20BridgeSource.Native,
|
||||||
|
ERC20BridgeSource.LiquidityProvider,
|
||||||
|
ERC20BridgeSource.Uniswap,
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Removes partial Native orders', () => {
|
||||||
|
const targetInput = new BigNumber(100);
|
||||||
|
const path = Path.create(
|
||||||
|
MarketOperation.Sell,
|
||||||
|
[
|
||||||
|
createFill(ERC20BridgeSource.Uniswap),
|
||||||
|
createFill(ERC20BridgeSource.LiquidityProvider),
|
||||||
|
createFill(ERC20BridgeSource.Native),
|
||||||
|
],
|
||||||
|
targetInput,
|
||||||
|
);
|
||||||
|
const fallback = Path.create(MarketOperation.Sell, [createFill(ERC20BridgeSource.Kyber)], targetInput);
|
||||||
|
path.addFallback(fallback);
|
||||||
|
const sources = path.fills.map(f => f.source);
|
||||||
|
expect(sources).to.deep.eq([
|
||||||
|
ERC20BridgeSource.Uniswap,
|
||||||
|
ERC20BridgeSource.LiquidityProvider,
|
||||||
|
ERC20BridgeSource.Kyber,
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
it('Handles duplicates', () => {
|
||||||
|
const targetInput = new BigNumber(100);
|
||||||
|
const path = Path.create(
|
||||||
|
MarketOperation.Sell,
|
||||||
|
[createFill(ERC20BridgeSource.Uniswap), createFill(ERC20BridgeSource.LiquidityProvider)],
|
||||||
|
targetInput,
|
||||||
|
);
|
||||||
|
const fallback = Path.create(MarketOperation.Sell, [createFill(ERC20BridgeSource.Uniswap)], targetInput);
|
||||||
|
path.addFallback(fallback);
|
||||||
|
const sources = path.fills.map(f => f.source);
|
||||||
|
expect(sources).to.deep.eq([ERC20BridgeSource.Uniswap, ERC20BridgeSource.LiquidityProvider]);
|
||||||
|
});
|
||||||
|
});
|
Loading…
x
Reference in New Issue
Block a user