-
Notifications
You must be signed in to change notification settings - Fork 434
feat: basic limit orders #2649
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
feat: basic limit orders #2649
Changes from all commits
Commits
Show all changes
13 commits
Select commit
Hold shift + click to select a range
5bb8632
feat: basic limit orders
JoaquinBattilana 17c959b
Merge branch 'main' into feat/switch-limit-2
JoaquinBattilana dd15ecf
feat: fixes allaround
JoaquinBattilana 6862f38
feat: fixes
JoaquinBattilana de28149
feat: fee
JoaquinBattilana 2a44d4d
feat: cancel order
JoaquinBattilana 5d3b88c
feat: merged with main
JoaquinBattilana fd57231
feat: fixed rates
JoaquinBattilana 7e8bae9
feat: desc texts
JoaquinBattilana 4e31821
feat: fix loading issue
JoaquinBattilana a519e9e
feat: small nits
JoaquinBattilana 0bbd7e2
chore: merged with main
JoaquinBattilana 567f90e
feat: tracking and arbitrum
JoaquinBattilana File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -157,4 +157,4 @@ | |
"budgetPercentIncreaseRed": 20, | ||
"showDetails": true | ||
} | ||
} | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
import { FixedPointNumber, Numberish } from './FixedPointNumber'; | ||
|
||
export class FPMath { | ||
static MaxUint256: FixedPointNumber = new FixedPointNumber( | ||
BigInt('0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff'), | ||
BigInt(0) | ||
); | ||
|
||
static ZERO = new FixedPointNumber(BigInt(0), BigInt(0)); | ||
|
||
static ONE = new FixedPointNumber(BigInt(1), BigInt(0)); | ||
|
||
static MINUS_ONE = new FixedPointNumber(BigInt(-1), BigInt(0)); | ||
|
||
private static maxScale(a: FixedPointNumber, b: FixedPointNumber): bigint { | ||
return a.scale > b.scale ? a.scale : b.scale; | ||
} | ||
|
||
static min(a: FixedPointNumber, b: FixedPointNumber): FixedPointNumber { | ||
const maxScale = FPMath.maxScale(a, b); | ||
const scaledA = a.scaleUp(maxScale); | ||
const scaledB = b.scaleUp(maxScale); | ||
return scaledA.value < scaledB.value ? a : b; | ||
} | ||
|
||
static max(a: FixedPointNumber, b: FixedPointNumber): FixedPointNumber { | ||
const maxScale = FPMath.maxScale(a, b); | ||
const scaledA = a.scaleUp(maxScale); | ||
const scaledB = b.scaleUp(maxScale); | ||
return scaledA.value > scaledB.value ? a : b; | ||
} | ||
|
||
static toFP(value: Numberish, _scale: Numberish): FixedPointNumber { | ||
const scale = Number(_scale); | ||
const stringValue = value.toString(); | ||
const [integerPart, decimalPart] = stringValue.split('.'); | ||
if (!decimalPart) { | ||
const zeroes = '0'.repeat(scale); | ||
return new FixedPointNumber(integerPart.concat(zeroes), scale); | ||
} | ||
const roundedDecimalPart = | ||
decimalPart.length > scale ? decimalPart.slice(0, scale) : decimalPart; | ||
const zeroes = '0'.repeat(scale - roundedDecimalPart.length); | ||
return new FixedPointNumber(integerPart.concat(roundedDecimalPart, zeroes), scale); | ||
} | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,230 @@ | ||
import invariant from 'tiny-invariant'; | ||
|
||
export type Numberish = number | string | bigint; | ||
export type FixedPointNumberValue<T extends FixedPointNumber = FixedPointNumber> = Numberish | T; | ||
|
||
export enum RoundMode { | ||
ROUND_DOWN, | ||
ROUND_UP, | ||
ROUND_HALF_UP, | ||
ROUND_HALF_DOWN, | ||
} | ||
|
||
interface IFixedPointNumber { | ||
add(value: FixedPointNumberValue): IFixedPointNumber; | ||
sub(value: FixedPointNumberValue): IFixedPointNumber; | ||
mul(value: FixedPointNumberValue): IFixedPointNumber; | ||
div(value: FixedPointNumberValue): IFixedPointNumber; | ||
pow(exp: FixedPointNumberValue): IFixedPointNumber; | ||
scaleUp(scale: number): IFixedPointNumber; | ||
scaleDown(scale: number, rounding: RoundMode): IFixedPointNumber; | ||
format(decimals?: number): string; | ||
} | ||
|
||
const countDecimals = (n: number) => { | ||
if (Math.floor(n) === n) return 0; | ||
return n.toString().split('.')[1].length || 0; | ||
}; | ||
|
||
export class FixedPointNumber implements IFixedPointNumber { | ||
readonly value: bigint; | ||
readonly scale: bigint; | ||
|
||
constructor(value: FixedPointNumberValue, scale?: Numberish) { | ||
if (value instanceof FixedPointNumber) { | ||
this.value = value.value; | ||
this.scale = value.scale; | ||
} else { | ||
invariant( | ||
scale !== undefined, | ||
'scale must be provided if initializing from other than a FixedPointNumber' | ||
); | ||
this.value = BigInt(value); | ||
this.scale = BigInt(scale); | ||
} | ||
} | ||
|
||
add(value: FixedPointNumberValue): FixedPointNumber { | ||
if (!(value instanceof FixedPointNumber)) { | ||
const wrappedValue = BigInt(value); | ||
return new FixedPointNumber(wrappedValue + this.value, this.scale); | ||
} | ||
if (this.scale === value.scale) { | ||
return new FixedPointNumber(this.value + value.value, this.scale); | ||
} | ||
if (this.scale > value.scale) { | ||
return new FixedPointNumber(this.value + value.scaleUp(this.scale).value, this.scale); | ||
} | ||
return new FixedPointNumber(this.scaleUp(value.scale).value + value.value, value.scale); | ||
} | ||
|
||
sub(value: FixedPointNumberValue): FixedPointNumber { | ||
if (!(value instanceof FixedPointNumber)) { | ||
const wrappedValue = BigInt(value); | ||
return new FixedPointNumber(this.value - wrappedValue, this.scale); | ||
} | ||
if (this.scale === value.scale) { | ||
return new FixedPointNumber(this.value - value.value, this.scale); | ||
} | ||
if (this.scale > value.scale) { | ||
return new FixedPointNumber(this.value - value.scaleUp(this.scale).value, this.scale); | ||
} | ||
return new FixedPointNumber(this.scaleUp(value.scale).value - value.value, value.scale); | ||
} | ||
|
||
mul(value: FixedPointNumberValue): FixedPointNumber { | ||
if (!(value instanceof FixedPointNumber)) { | ||
const wrappedValue = BigInt(value); | ||
return new FixedPointNumber(this.value * wrappedValue, this.scale * BigInt(2)); | ||
} | ||
return new FixedPointNumber(this.value * value.value, this.scale + value.scale); | ||
} | ||
|
||
scaleMul(value: Numberish): FixedPointNumber { | ||
const wrappedValue = BigInt(value); | ||
return new FixedPointNumber(this.value * wrappedValue, this.scale); | ||
} | ||
|
||
div(value: FixedPointNumberValue): FixedPointNumber { | ||
if (!(value instanceof FixedPointNumber)) { | ||
const wrappedValue = BigInt(value); | ||
return new FixedPointNumber(this.value / wrappedValue, 0); | ||
} | ||
const dividend = this.scale < value.scale ? this.scaleUp(value.scale) : this; | ||
const dividendWithMinPrecision = | ||
dividend.scale - value.scale < BigInt(3) ? this.scaleUp(dividend.scale + BigInt(3)) : this; | ||
return new FixedPointNumber( | ||
dividendWithMinPrecision.value / value.value, | ||
dividendWithMinPrecision.scale - value.scale | ||
); | ||
} | ||
|
||
scaleDiv(value: Numberish): FixedPointNumber { | ||
const wrappedValue = BigInt(value); | ||
return new FixedPointNumber(this.value / wrappedValue, this.scale); | ||
} | ||
|
||
pow(exp: Numberish): FixedPointNumber { | ||
const wrappedExp = BigInt(exp); | ||
return new FixedPointNumber(this.value ** BigInt(exp), this.scale ** wrappedExp); | ||
} | ||
|
||
scaleit(scale: Numberish): FixedPointNumber { | ||
const wrappedScale = BigInt(scale); | ||
if (wrappedScale === this.scale) { | ||
return this; | ||
} | ||
if (wrappedScale > this.scale) { | ||
return this.scaleUp(scale); | ||
} | ||
return this.scaleDown(scale, RoundMode.ROUND_DOWN); | ||
} | ||
|
||
scaleUp(scale: Numberish): FixedPointNumber { | ||
const wrappedScale = BigInt(scale); | ||
invariant(wrappedScale >= this.scale, 'scale must be higher or equal'); | ||
return new FixedPointNumber( | ||
this.value * BigInt(10) ** BigInt(wrappedScale - this.scale), | ||
scale | ||
); | ||
} | ||
|
||
scaleDown(scale: Numberish, rounding: RoundMode): FixedPointNumber { | ||
const wrappedScale = BigInt(scale); | ||
if (wrappedScale === this.scale) return this; | ||
// we leave 1 extra decimal to handle rounding | ||
const preNewValue = this.value / BigInt(10) ** BigInt(this.scale - wrappedScale - BigInt(1)); | ||
switch (rounding) { | ||
case RoundMode.ROUND_DOWN: | ||
return new FixedPointNumber(preNewValue / BigInt(10), wrappedScale); | ||
case RoundMode.ROUND_UP: | ||
return new FixedPointNumber(preNewValue / BigInt(10) + BigInt(1), wrappedScale); | ||
case RoundMode.ROUND_HALF_UP: | ||
return new FixedPointNumber((preNewValue + BigInt(5)) / BigInt(10), wrappedScale); | ||
case RoundMode.ROUND_HALF_DOWN: | ||
return new FixedPointNumber((preNewValue + BigInt(4)) / BigInt(10), wrappedScale); | ||
} | ||
} | ||
|
||
eq(value: FixedPointNumberValue): boolean { | ||
if (value instanceof FixedPointNumber) { | ||
if (this.scale > value.scale) { | ||
return this.value === value.value * BigInt(10) * (this.scale - value.scale); | ||
} | ||
return this.value * BigInt(10) ** (value.scale - this.scale) === value.value; | ||
} | ||
return this.value === BigInt(value); | ||
} | ||
|
||
lte(value: FixedPointNumberValue): boolean { | ||
if (value instanceof FixedPointNumber) { | ||
if (this.scale > value.scale) { | ||
return this.value <= value.value * BigInt(10) ** (this.scale - value.scale); | ||
} | ||
return this.value * BigInt(10) ** (value.scale - this.scale) <= value.value; | ||
} | ||
return this.value <= BigInt(value); | ||
} | ||
|
||
gte(value: FixedPointNumberValue): boolean { | ||
if (value instanceof FixedPointNumber) { | ||
if (this.scale > value.scale) { | ||
return this.value >= value.value * BigInt(10) ** (this.scale - value.scale); | ||
} | ||
return this.value * BigInt(10) ** (value.scale - this.scale) >= value.value; | ||
} | ||
return this.value >= BigInt(value); | ||
} | ||
|
||
lt(value: FixedPointNumberValue): boolean { | ||
if (value instanceof FixedPointNumber) { | ||
if (this.scale > value.scale) { | ||
return this.value < value.value * BigInt(10) ** (this.scale - value.scale); | ||
} | ||
return this.value * BigInt(10) ** (value.scale - this.scale) < value.value; | ||
} | ||
return this.value < BigInt(value); | ||
} | ||
|
||
gt(value: FixedPointNumberValue): boolean { | ||
if (value instanceof FixedPointNumber) { | ||
if (this.scale > value.scale) { | ||
return this.value > value.value * BigInt(10) ** (this.scale - value.scale); | ||
} | ||
return this.value * BigInt(10) ** (value.scale - this.scale) > value.value; | ||
} | ||
return this.value > BigInt(value); | ||
} | ||
|
||
percent(percent: number): FixedPointNumber { | ||
const decimals = countDecimals(percent); | ||
const integerPercent = BigInt(percent * 10 ** decimals); | ||
const scaledPercent = integerPercent * BigInt(10) ** this.scale; | ||
const scaledDivisor = BigInt(10) ** (this.scale + BigInt(decimals)); | ||
return this.scaleMul(scaledPercent).scaleDiv(scaledDivisor); | ||
} | ||
|
||
format(decimals?: number): string { | ||
const stringValue = this.value.toString(); | ||
const positivePart = this.value < BigInt(0) ? stringValue.substring(1) : stringValue; | ||
const paddedPositivePart = positivePart.padStart(Number(this.scale) + 1, '0'); | ||
const positiveNumbers = paddedPositivePart.length - Number(this.scale); | ||
const positiveWithDecimals = | ||
paddedPositivePart.length === positiveNumbers | ||
? paddedPositivePart.slice(0, positiveNumbers) | ||
: paddedPositivePart.slice(0, positiveNumbers) + | ||
'.' + | ||
paddedPositivePart.slice( | ||
positiveNumbers, | ||
decimals ? positiveNumbers + decimals : undefined | ||
); | ||
if (this.value < BigInt(0)) { | ||
return '-' + positiveWithDecimals; | ||
} | ||
return positiveWithDecimals; | ||
} | ||
|
||
toNumber(): number { | ||
return Number(this.format()); | ||
} | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
import { Trans } from '@lingui/macro'; | ||
|
||
import { TextWithTooltip } from '../TextWithTooltip'; | ||
|
||
export const NetworkCostTooltip = () => { | ||
return ( | ||
<TextWithTooltip variant="caption" text={<Trans>Network costs</Trans>}> | ||
<Trans> | ||
This is the cost of settling your order on-chain, including gas and any LP fees. | ||
</Trans> | ||
</TextWithTooltip> | ||
); | ||
}; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
import { Trans } from '@lingui/macro'; | ||
|
||
import { Link } from '../primitives/Link'; | ||
import { TextWithTooltip } from '../TextWithTooltip'; | ||
|
||
export const SwapFeeTooltip = () => { | ||
return ( | ||
<TextWithTooltip variant="caption" text={<Trans>Fee</Trans>}> | ||
<Trans> | ||
Fees help support the user experience and security of the Aave application.{' '} | ||
<Link | ||
href="https://aave.com/docs/developers/smart-contracts/swap-features" | ||
target="_blank" | ||
rel="noopener" | ||
> | ||
Learn more. | ||
</Link> | ||
</Trans> | ||
</TextWithTooltip> | ||
); | ||
}; |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
thanks for adding