Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
S
swap-v2-sdk
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
LuckySwap
swap-v2-sdk
Commits
1fcc0a59
Unverified
Commit
1fcc0a59
authored
Jun 10, 2019
by
Noah Zinsmeister
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
finalize MVP beta release
add transact logic augment tests
parent
96a412f6
Changes
21
Hide whitespace changes
Inline
Side-by-side
Showing
21 changed files
with
1224 additions
and
297 deletions
+1224
-297
_utils.ts
src/__tests__/_utils.ts
+10
-9
computation.ts
src/__tests__/computation.ts
+69
-51
data.ts
src/__tests__/data.ts
+18
-5
format.ts
src/__tests__/format.ts
+3
-3
orchestration.ts
src/__tests__/orchestration.ts
+17
-12
transact.ts
src/__tests__/transact.ts
+24
-0
index.ts
src/_utils/index.ts
+13
-20
_utils.ts
src/computation/_utils.ts
+2
-93
market.ts
src/computation/market.ts
+69
-7
trade.ts
src/computation/trade.ts
+24
-20
ERC20.json
src/constants/abis/ERC20.json
+18
-3
EXCHANGE.json
src/constants/abis/EXCHANGE.json
+460
-0
FACTORY.json
src/constants/abis/FACTORY.json
+68
-5
index.ts
src/constants/index.ts
+44
-18
index.ts
src/data/index.ts
+36
-22
index.ts
src/format/index.ts
+8
-8
index.ts
src/index.ts
+5
-1
index.ts
src/orchestration/index.ts
+102
-15
index.ts
src/transact/index.ts
+205
-0
types.ts
src/types.ts
+28
-4
tsconfig.json
tsconfig.json
+1
-1
No files found.
src/__tests__/
utils/index
.ts
→
src/__tests__/
_utils
.ts
View file @
1fcc0a59
import
BigNumber
from
'
bignumber.js
'
import
{
ethers
}
from
'
ethers
'
import
{
BigNumberish
}
from
'
../
../
types
'
import
{
normalizeBigNumberish
}
from
'
../
../
_utils
'
import
{
BigNumberish
}
from
'
../types
'
import
{
normalizeBigNumberish
}
from
'
../_utils
'
interface
TestCase
{
input
:
BigNumberish
expectedOutput
:
BigNumber
}
function
constructTestCase
(
input
:
BigNumberish
,
expectedOutput
:
BigNumber
):
TestCase
{
return
{
input
,
expectedOutput
}
}
...
...
@@ -52,9 +53,9 @@ describe('normalizeBigNumberish', (): void => {
describe
(
'
number
'
,
():
void
=>
{
const
expectedSuccesses
:
TestCase
[]
=
[
constructTestCase
(
0
,
new
BigNumber
(
0
)),
constructTestCase
(
1
,
new
BigNumber
(
1
)),
constructTestCase
(
1.234
,
new
BigNumber
(
1.234
))
constructTestCase
(
0
,
new
BigNumber
(
'
0
'
)),
constructTestCase
(
1
,
new
BigNumber
(
'
1
'
)),
constructTestCase
(
1.234
,
new
BigNumber
(
'
1.234
'
))
]
const
expectedFailures
:
number
[]
=
[
NaN
,
Infinity
]
...
...
@@ -64,8 +65,8 @@ describe('normalizeBigNumberish', (): void => {
describe
(
'
BigNumber
'
,
():
void
=>
{
const
expectedSuccesses
:
TestCase
[]
=
[
constructTestCase
(
new
BigNumber
(
0
),
new
BigNumber
(
0
)),
constructTestCase
(
new
BigNumber
(
1
),
new
BigNumber
(
1
)),
constructTestCase
(
new
BigNumber
(
0
),
new
BigNumber
(
'
0
'
)),
constructTestCase
(
new
BigNumber
(
1
),
new
BigNumber
(
'
1
'
)),
constructTestCase
(
new
BigNumber
(
'
1.234
'
),
new
BigNumber
(
'
1.234
'
))
]
const
expectedFailures
:
BigNumber
[]
=
[
new
BigNumber
(
NaN
)]
...
...
@@ -76,8 +77,8 @@ describe('normalizeBigNumberish', (): void => {
describe
(
'
ethers.utils.BigNumber
'
,
():
void
=>
{
const
expectedSuccesses
:
TestCase
[]
=
[
constructTestCase
(
ethers
.
constants
.
Zero
,
new
BigNumber
(
0
)),
constructTestCase
(
ethers
.
constants
.
One
,
new
BigNumber
(
1
)),
constructTestCase
(
ethers
.
constants
.
Zero
,
new
BigNumber
(
'
0
'
)),
constructTestCase
(
ethers
.
constants
.
One
,
new
BigNumber
(
'
1
'
)),
constructTestCase
(
ethers
.
utils
.
bigNumberify
(
'
1234
'
),
new
BigNumber
(
'
1234
'
)),
constructTestCase
(
ethers
.
utils
.
parseUnits
(
'
1.234
'
,
3
),
new
BigNumber
(
'
1234
'
))
]
...
...
src/__tests__/computation.ts
View file @
1fcc0a59
import
BigNumber
from
'
bignumber.js
'
import
{
BigNumberish
,
TokenReserves
,
MarketDetails
,
OptionalReserves
,
TradeDetails
}
from
'
../types
'
import
{
TRADE_
TYPE
,
TRADE_EXACT
,
_10
}
from
'
../constants
'
import
{
TRADE_
EXACT
}
from
'
../constants
'
import
{
getMarketDetails
,
getTradeDetails
}
from
'
../computation
'
function
constructTokenReserves
(
...
...
@@ -16,80 +14,55 @@ function constructTokenReserves(
}
}
const
DAIReserves
:
TokenReserves
=
constructTokenReserves
(
18
,
'
4039700561005906883487
'
,
'
1094055210563660633471343
'
)
const
USDCReserves
:
TokenReserves
=
constructTokenReserves
(
6
,
'
1076592291503763426634
'
,
'
292657693901
'
)
function
testMarketRates
(
tradeType
:
TRADE_TYPE
,
inputTokenReserves
:
OptionalReserves
,
outputTokenReserves
:
OptionalReserves
,
expectedMarketRate
:
string
,
expectedMarketRateInverted
:
string
):
void
{
test
(
'
not inverted
'
,
():
void
=>
{
const
marketDetails
:
MarketDetails
=
getMarketDetails
(
tradeType
,
inputTokenReserves
,
outputTokenReserves
)
test
(
'
normal
'
,
():
void
=>
{
const
marketDetails
:
MarketDetails
=
getMarketDetails
(
inputTokenReserves
,
outputTokenReserves
)
expect
(
marketDetails
.
marketRate
.
rate
.
toFixed
(
18
)).
toBe
(
expectedMarketRate
)
expect
(
marketDetails
.
marketRate
.
rateInverted
.
toFixed
(
18
)).
toBe
(
expectedMarketRateInverted
)
})
test
(
'
manually inverted
'
,
():
void
=>
{
const
tradeTypeInverted
=
tradeType
===
TRADE_TYPE
.
ETH_TO_TOKEN
?
TRADE_TYPE
.
TOKEN_TO_ETH
:
TRADE_TYPE
.
ETH_TO_TOKEN
const
marketDetails
:
MarketDetails
=
getMarketDetails
(
tradeType
===
TRADE_TYPE
.
TOKEN_TO_TOKEN
?
TRADE_TYPE
.
TOKEN_TO_TOKEN
:
tradeTypeInverted
,
outputTokenReserves
,
inputTokenReserves
)
test
(
'
inverted
'
,
():
void
=>
{
const
marketDetails
:
MarketDetails
=
getMarketDetails
(
outputTokenReserves
,
inputTokenReserves
)
expect
(
marketDetails
.
marketRate
.
rate
.
toFixed
(
18
)).
toBe
(
expectedMarketRateInverted
)
expect
(
marketDetails
.
marketRate
.
rateInverted
.
toFixed
(
18
)).
toBe
(
expectedMarketRate
)
})
}
describe
(
'
getMarketDetails
'
,
():
void
=>
{
describe
(
'
dummy ETH/DAI and DAI/ETH
'
,
():
void
=>
{
const
tokenReserves
:
TokenReserves
=
constructTokenReserves
(
18
,
'
4039700561005906883487
'
,
'
1094055210563660633471343
'
)
describe
(
'
DAI
'
,
():
void
=>
{
const
expectedMarketRate
=
'
270.825818409480102284
'
const
expectedMarketRateInverted
=
'
0.003692410147130181
'
testMarketRates
(
TRADE_TYPE
.
ETH_TO_TOKEN
,
null
,
tokenReserves
,
expectedMarketRate
,
expectedMarketRateInverted
)
testMarketRates
(
undefined
,
DAIReserves
,
expectedMarketRate
,
expectedMarketRateInverted
)
})
describe
(
'
dummy ETH/USDC and USDC/ETH
'
,
():
void
=>
{
const
tokenReserves
:
TokenReserves
=
constructTokenReserves
(
6
,
'
1076592291503763426634
'
,
'
292657693901
'
)
describe
(
'
USDC
'
,
():
void
=>
{
const
expectedMarketRate
=
'
0.003678674143683891
'
const
expectedMarketRateInverted
=
'
271.837069808684359442
'
testMarketRates
(
TRADE_TYPE
.
TOKEN_TO_ETH
,
tokenReserves
,
null
,
expectedMarketRate
,
expectedMarketRateInverted
)
testMarketRates
(
USDCReserves
,
undefined
,
expectedMarketRate
,
expectedMarketRateInverted
)
})
describe
(
'
dummy DAI/USDC and USDC/DAI
'
,
():
void
=>
{
const
DAITokenReserves
:
TokenReserves
=
constructTokenReserves
(
18
,
'
4039700561005906883487
'
,
'
1094055210563660633471343
'
)
const
USDCTokenReserves
:
TokenReserves
=
constructTokenReserves
(
6
,
'
1076592291503763426634
'
,
'
292657693901
'
)
describe
(
'
DAI and USDC
'
,
():
void
=>
{
const
expectedMarketRate
=
'
1.003733954927721392
'
const
expectedMarketRateInverted
=
'
0.996279935624983143
'
testMarketRates
(
TRADE_TYPE
.
TOKEN_TO_TOKEN
,
DAITokenReserves
,
USDCTokenReserves
,
expectedMarketRate
,
expectedMarketRateInverted
)
testMarketRates
(
DAIReserves
,
USDCReserves
,
expectedMarketRate
,
expectedMarketRateInverted
)
})
})
function
testTradeDetails
(
tradeExact
:
TRADE_EXACT
,
tradeAmount
:
BigNumber
,
tradeAmount
:
BigNumber
ish
,
marketDetails
:
MarketDetails
,
expectedInputValue
:
string
,
expectedOutputValue
:
string
,
expectedExecutionRate
:
string
,
expectedExecutionRateInverted
:
string
,
expectedMarketRateSlippage
:
string
,
...
...
@@ -99,6 +72,8 @@ function testTradeDetails(
const
tradeDetails
:
TradeDetails
=
getTradeDetails
(
tradeExact
,
tradeAmount
,
marketDetails
)
expect
(
tradeDetails
.
inputAmount
.
amount
.
toFixed
(
0
)).
toBe
(
expectedInputValue
)
expect
(
tradeDetails
.
outputAmount
.
amount
.
toFixed
(
0
)).
toBe
(
expectedOutputValue
)
expect
(
tradeDetails
.
executionRate
.
rate
.
toFixed
(
18
)).
toBe
(
expectedExecutionRate
)
expect
(
tradeDetails
.
executionRate
.
rateInverted
.
toFixed
(
18
)).
toBe
(
expectedExecutionRateInverted
)
...
...
@@ -108,25 +83,68 @@ function testTradeDetails(
}
describe
(
'
getTradeDetails
'
,
():
void
=>
{
describe
(
'
dummy ETH/DAI and DAI/ETH
'
,
():
void
=>
{
const
tokenReserves
:
TokenReserves
=
constructTokenReserves
(
18
,
'
4039700561005906883487
'
,
'
1094055210563660633471343
'
)
describe
(
'
ETH for DAI exact output
'
,
():
void
=>
{
const
marketDetails
:
MarketDetails
=
getMarketDetails
(
undefined
,
DAIReserves
)
const
expectedInputValue
=
'
370385925334764803
'
const
expectedOutputValue
=
'
100000000000000000000
'
const
expectedExecutionRate
=
'
269.988660907180258319
'
const
expectedExecutionRateInverted
=
'
0.003703859253347648
'
const
expectedMarketRateSlippage
=
'
1.830727602963479922
'
const
expectedExecutionRateSlippage
=
'
30.911288562381013644
'
const
marketDetails
:
MarketDetails
=
getMarketDetails
(
TRADE_TYPE
.
ETH_TO_TOKEN
,
null
,
tokenReserves
)
testTradeDetails
(
TRADE_EXACT
.
OUTPUT
,
new
BigNumber
(
100
).
multipliedBy
(
_10
.
exponentiatedBy
(
18
)),
expectedOutputValue
,
marketDetails
,
expectedInputValue
,
expectedOutputValue
,
expectedExecutionRate
,
expectedExecutionRateInverted
,
expectedMarketRateSlippage
,
expectedExecutionRateSlippage
)
})
describe
(
'
DAI for ETH exact output
'
,
():
void
=>
{
const
marketDetails
:
MarketDetails
=
getMarketDetails
(
DAIReserves
,
undefined
)
const
expectedInputValue
=
'
271708000072010674989
'
const
expectedOutputValue
=
'
1000000000000000000
'
const
expectedExecutionRate
=
'
0.003680421628126409
'
const
expectedExecutionRateInverted
=
'
271.708000072010674989
'
const
expectedMarketRateSlippage
=
'
4.957694170529155578
'
const
expectedExecutionRateSlippage
=
'
32.468004707141566275
'
testTradeDetails
(
TRADE_EXACT
.
OUTPUT
,
expectedOutputValue
,
marketDetails
,
expectedInputValue
,
expectedOutputValue
,
expectedExecutionRate
,
expectedExecutionRateInverted
,
expectedMarketRateSlippage
,
expectedExecutionRateSlippage
)
})
describe
(
'
DAI for USDC exact input
'
,
():
void
=>
{
const
marketDetails
:
MarketDetails
=
getMarketDetails
(
DAIReserves
,
USDCReserves
)
const
expectedInputValue
=
'
1000000000000000000
'
const
expectedOutputValue
=
'
997716
'
const
expectedExecutionRate
=
'
0.997716000000000000
'
const
expectedExecutionRateInverted
=
'
1.002289228598118102
'
const
expectedMarketRateSlippage
=
'
0.086538655703617094
'
const
expectedExecutionRateSlippage
=
'
59.955677479843185050
'
testTradeDetails
(
TRADE_EXACT
.
INPUT
,
expectedInputValue
,
marketDetails
,
expectedInputValue
,
expectedOutputValue
,
expectedExecutionRate
,
expectedExecutionRateInverted
,
expectedMarketRateSlippage
,
...
...
src/__tests__/data.ts
View file @
1fcc0a59
import
{
TokenReserves
,
Token
}
from
'
../types
'
import
{
ETH
as
_ETH
}
from
'
../constants
'
import
{
getTokenReserves
}
from
'
../data
'
import
{
Token
,
TokenReservesNormalized
}
from
'
../types
'
import
{
ETH
as
_ETH
,
_CHAIN_ID_NAME
}
from
'
../constants
'
import
{
getTokenReserves
,
getEthToken
}
from
'
../data
'
import
{
ethers
}
from
'
ethers
'
const
ETH
:
Token
=
{
chainId
:
1
,
...
...
@@ -21,9 +22,17 @@ const DAI_EXCHANGE: Token = {
}
describe
(
'
getTokenReserves
'
,
():
void
=>
{
jest
.
setTimeout
(
10000
)
// 10 seconds
test
(
'
DAI
'
,
async
(
done
:
jest
.
DoneCallback
):
Promise
<
void
>
=>
{
jest
.
setTimeout
(
10000
)
// 10 seconds
const
tokenReserves
:
TokenReserves
=
await
getTokenReserves
(
DAI
.
address
as
string
)
const
tokenReserves
:
TokenReservesNormalized
=
await
getTokenReserves
(
DAI
.
address
as
string
)
const
tokenReservesProvider
:
TokenReservesNormalized
=
await
getTokenReserves
(
DAI
.
address
as
string
,
ethers
.
getDefaultProvider
(
_CHAIN_ID_NAME
[
1
])
)
expect
(
tokenReserves
.
token
).
toEqual
(
tokenReservesProvider
.
token
)
expect
(
tokenReserves
.
token
).
toEqual
(
DAI
)
expect
(
tokenReserves
.
exchange
).
toEqual
(
DAI_EXCHANGE
)
...
...
@@ -35,3 +44,7 @@ describe('getTokenReserves', (): void => {
done
()
})
})
test
(
'
getEthToken
'
,
():
void
=>
{
expect
(
getEthToken
(
1
)).
toEqual
(
ETH
)
})
src/__tests__/format.ts
View file @
1fcc0a59
...
...
@@ -2,11 +2,11 @@ import BigInteger from 'bignumber.js'
import
{
FlexibleFormat
,
FormatSignificantOptions
,
FormatFixedOptions
}
from
'
../types
'
import
{
formatSignificant
,
formatSignificantDecimals
,
formatFixed
,
formatFixedDecimals
}
from
'
../format
'
import
{
FIXED_UNDERFLOW_BEHAVIOR
,
ROUNDING_MODE
}
from
'
../constants
'
import
{
FIXED_UNDERFLOW_BEHAVIOR
,
_
ROUNDING_MODE
}
from
'
../constants
'
function
constructFormatSignificantOptions
(
significantDigits
:
number
,
roundingMode
:
BigInteger
.
RoundingMode
=
ROUNDING_MODE
,
roundingMode
:
BigInteger
.
RoundingMode
=
_
ROUNDING_MODE
,
forceIntegerSignificance
:
boolean
=
false
,
format
:
FlexibleFormat
=
false
):
FormatSignificantOptions
{
...
...
@@ -20,7 +20,7 @@ function constructFormatSignificantOptions(
function
constructFormatFixedOptions
(
decimalPlaces
:
number
,
roundingMode
:
BigInteger
.
RoundingMode
=
ROUNDING_MODE
,
roundingMode
:
BigInteger
.
RoundingMode
=
_
ROUNDING_MODE
,
dropTrailingZeros
:
boolean
=
true
,
underflowBehavior
:
FIXED_UNDERFLOW_BEHAVIOR
=
FIXED_UNDERFLOW_BEHAVIOR
.
ONE_DIGIT
,
format
:
FlexibleFormat
=
false
...
...
src/__tests__/orchestration.ts
View file @
1fcc0a59
import
BigNumber
from
'
bignumber.js
'
import
{
TradeDetails
}
from
'
../types
'
import
{
_10
,
ETH
,
TRADE_TYPE
,
TRADE_EXACT
}
from
'
../constants
'
import
{
getTrade
}
from
'
../orchestration
'
import
{
tradeExactEthForTokens
}
from
'
../orchestration
'
import
{
TRADE_TYPE
,
TRADE_EXACT
}
from
'
../constants
'
describe
(
'
tradeExactEthForTokens
'
,
():
void
=>
{
jest
.
setTimeout
(
10000
)
// 10 seconds
describe
(
'
getTrade
'
,
():
void
=>
{
test
(
'
DAI
'
,
async
(
done
:
jest
.
DoneCallback
):
Promise
<
void
>
=>
{
jest
.
setTimeout
(
10000
)
// 10 seconds
const
tradeDetails
:
TradeDetails
=
await
getTrade
(
ETH
,
const
tradeDetails
:
TradeDetails
=
await
tradeExactEthForTokens
(
'
0x89d24A6b4CcB1B6fAA2625fE562bDD9a23260359
'
,
TRADE_TYPE
.
ETH_TO_TOKEN
,
TRADE_EXACT
.
OUTPUT
,
new
BigNumber
(
100
).
multipliedBy
(
_10
.
exponentiatedBy
(
18
))
'
1000000000000000000
'
)
expect
(
tradeDetails
.
inputAmount
).
toBeTruthy
()
expect
(
tradeDetails
.
tradeType
).
toEqual
(
TRADE_TYPE
.
ETH_TO_TOKEN
)
expect
(
tradeDetails
.
tradeExact
).
toEqual
(
TRADE_EXACT
.
INPUT
)
expect
(
tradeDetails
.
inputAmount
.
amount
.
toFixed
()).
toEqual
(
'
1000000000000000000
'
)
expect
(
tradeDetails
.
outputAmount
.
amount
).
toBeTruthy
()
expect
(
tradeDetails
.
executionRate
.
rate
).
toBeTruthy
()
expect
(
tradeDetails
.
executionRate
.
rateInverted
).
toBeTruthy
()
expect
(
tradeDetails
.
marketRateSlippage
).
toBeTruthy
()
expect
(
tradeDetails
.
executionRateSlippage
).
toBeTruthy
()
done
()
})
})
src/__tests__/transact.ts
0 → 100644
View file @
1fcc0a59
import
{
TradeDetails
,
ExecutionDetails
}
from
'
../types
'
import
{
TRADE_METHODS
,
TRADE_METHOD_IDS
}
from
'
../constants
'
import
{
tradeExactEthForTokens
}
from
'
../orchestration
'
import
{
getExecutionDetails
}
from
'
../transact
'
describe
(
'
tradeExactEthForTokens
'
,
():
void
=>
{
jest
.
setTimeout
(
10000
)
// 10 seconds
test
(
'
DAI
'
,
async
(
done
:
jest
.
DoneCallback
):
Promise
<
void
>
=>
{
const
tradeDetails
:
TradeDetails
=
await
tradeExactEthForTokens
(
'
0x89d24A6b4CcB1B6fAA2625fE562bDD9a23260359
'
,
'
1000000000000000000
'
)
const
executionDetails
:
ExecutionDetails
=
getExecutionDetails
(
tradeDetails
)
expect
(
executionDetails
.
exchangeAddress
).
toEqual
(
'
0x09cabEC1eAd1c0Ba254B09efb3EE13841712bE14
'
)
expect
(
executionDetails
.
methodName
).
toEqual
(
TRADE_METHODS
.
ethToTokenSwapInput
)
expect
(
executionDetails
.
methodId
).
toEqual
(
TRADE_METHOD_IDS
[
TRADE_METHODS
.
ethToTokenSwapInput
])
expect
(
executionDetails
.
value
.
toFixed
()).
toEqual
(
'
1000000000000000000
'
)
done
()
})
})
src/_utils/index.ts
View file @
1fcc0a59
...
...
@@ -2,11 +2,10 @@ import BigNumber from 'bignumber.js'
import
{
ethers
}
from
'
ethers
'
import
{
BigNumberish
}
from
'
../types
'
import
{
_0
,
MAX_UINT8
,
MAX_UINT256
}
from
'
../constants
'
import
{
_0
,
_MAX_UINT8
,
_
MAX_UINT256
}
from
'
../constants
'
// check(s) that number(s) is(are) uint8(s)
function
ensureUInt8
(
number
:
number
):
void
{
if
(
!
Number
.
isInteger
(
number
)
||
number
<
0
||
number
>
MAX_UINT8
)
{
if
(
!
Number
.
isInteger
(
number
)
||
number
<
0
||
number
>
_
MAX_UINT8
)
{
throw
Error
(
`Passed number '
${
number
}
' is not a valid uint8.`
)
}
}
...
...
@@ -15,9 +14,8 @@ export function ensureAllUInt8(numbers: number[]): void {
numbers
.
forEach
(
ensureUInt8
)
}
// check(s) that BigNumber(s) is(are) uint256(s)
function
ensureUInt256
(
bigNumber
:
BigNumber
):
void
{
if
(
!
bigNumber
.
isInteger
()
||
bigNumber
.
isLessThan
(
_0
)
||
bigNumber
.
isGreaterThan
(
MAX_UINT256
))
{
if
(
!
bigNumber
.
isInteger
()
||
bigNumber
.
isLessThan
(
_0
)
||
bigNumber
.
isGreaterThan
(
_
MAX_UINT256
))
{
throw
Error
(
`Passed bigNumber '
${
bigNumber
}
' is not a valid uint256.`
)
}
}
...
...
@@ -26,31 +24,26 @@ export function ensureAllUInt256(bigNumbers: BigNumber[]): void {
bigNumbers
.
forEach
(
ensureUInt256
)
}
// check that number is valid decimals places/significant digits
export
function
ensureBoundedInteger
(
number
:
number
,
bounds
:
number
|
number
[]):
void
{
const
[
minimum
,
maximum
]:
[
number
,
number
]
=
typeof
bounds
===
'
number
'
?
[
0
,
bounds
]
:
[
bounds
[
0
],
bounds
[
1
]]
if
(
!
Number
.
isInteger
(
number
)
||
number
<
minimum
||
number
>
maximum
)
{
throw
Error
(
`Passed number '
${
number
}
' is not an integer between '
${
minimum
}
' and '
${
maximum
}
'
, inclusive
.`
)
throw
Error
(
`Passed number '
${
number
}
' is not an integer between '
${
minimum
}
' and '
${
maximum
}
'
(inclusive)
.`
)
}
}
export
function
normalizeBigNumberish
(
bigNumberish
:
BigNumberish
):
BigNumber
{
try
{
const
bigNumber
=
BigNumber
.
isBigNumber
(
bigNumberish
)
?
bigNumberish
:
new
BigNumber
(
bigNumberish
.
toString
())
if
(
!
bigNumber
.
isFinite
())
{
throw
Error
}
return
bigNumber
}
catch
(
error
)
{
throw
Error
(
`Passed bigNumberish '
${
bigNumberish
}
' of type '
${
typeof
bigNumberish
}
' is invalid. Error: '
${
error
}
'.`
)
const
bigNumber
:
BigNumber
=
BigNumber
.
isBigNumber
(
bigNumberish
)
?
bigNumberish
:
new
BigNumber
(
bigNumberish
.
toString
())
if
(
!
bigNumber
.
isFinite
())
{
throw
Error
(
`Passed bigNumberish '
${
bigNumberish
}
' of type '
${
typeof
bigNumberish
}
' is not valid.`
)
}
return
bigNumber
}
export
function
normalizeAddress
(
address
:
string
):
string
{
try
{
return
ethers
.
utils
.
getAddress
(
address
.
toLowerCase
())
}
catch
{
throw
Error
(
`Passed address '
${
address
}
' is not valid.`
)
}
return
ethers
.
utils
.
getAddress
(
address
.
toLowerCase
())
}
src/computation/_utils.ts
View file @
1fcc0a59
import
BigNumber
from
'
bignumber.js
'
import
{
TokenAmount
,
TokenAmountNormalized
,
TokenReserves
,
areTokenReserves
,
areETHReserves
,
OptionalReserves
,
TokenReservesNormalized
,
_ParsedOptionalReserves
,
_DecimalRate
,
_AnyRate
}
from
'
../types
'
import
{
_1
,
_10
,
_10000
,
TRADE_TYPE
,
ETH_TOKEN
}
from
'
../constants
'
import
{
ensureAllUInt8
,
ensureAllUInt256
,
normalizeBigNumberish
}
from
'
../_utils
'
function
normalizeTokenAmount
(
tokenAmount
:
TokenAmount
):
TokenAmountNormalized
{
ensureAllUInt8
([
tokenAmount
.
token
.
decimals
])
const
normalizedAmount
:
BigNumber
=
normalizeBigNumberish
(
tokenAmount
.
amount
)
ensureAllUInt256
([
normalizedAmount
])
return
{
token
:
{
...
tokenAmount
.
token
},
amount
:
normalizedAmount
}
}
function
normalizeTokenReserves
(
tokenReserves
:
TokenReserves
):
TokenReservesNormalized
{
ensureAllUInt8
([
tokenReserves
.
token
.
decimals
])
if
(
tokenReserves
.
exchange
)
{
ensureAllUInt8
([
tokenReserves
.
exchange
.
decimals
])
}
return
{
token
:
{
...
tokenReserves
.
token
},
...(
tokenReserves
.
exchange
?
{
...
tokenReserves
.
exchange
}
:
{}),
ethReserve
:
normalizeTokenAmount
(
tokenReserves
.
ethReserve
),
tokenReserve
:
normalizeTokenAmount
(
tokenReserves
.
tokenReserve
)
}
}
function
ensureTradeTypesMatch
(
computedTradeType
:
TRADE_TYPE
,
passedTradeType
?:
TRADE_TYPE
):
never
|
void
{
if
(
passedTradeType
&&
passedTradeType
!==
computedTradeType
)
{
throw
Error
(
`passedTradeType '
${
passedTradeType
}
' does not match computedTradeType '
${
computedTradeType
}
'.`
)
}
}
export
function
parseOptionalReserves
(
optionalReservesInput
:
OptionalReserves
,
optionalReservesOutput
:
OptionalReserves
,
passedTradeType
?:
TRADE_TYPE
):
_ParsedOptionalReserves
{
if
(
areTokenReserves
(
optionalReservesInput
)
&&
areTokenReserves
(
optionalReservesOutput
))
{
const
computedTradeType
:
TRADE_TYPE
=
TRADE_TYPE
.
TOKEN_TO_TOKEN
ensureTradeTypesMatch
(
computedTradeType
,
passedTradeType
)
return
{
tradeType
:
computedTradeType
,
inputReserves
:
normalizeTokenReserves
(
optionalReservesInput
),
outputReserves
:
normalizeTokenReserves
(
optionalReservesOutput
)
}
}
else
if
(
areTokenReserves
(
optionalReservesInput
)
&&
!
areTokenReserves
(
optionalReservesOutput
))
{
const
computedTradeType
:
TRADE_TYPE
=
TRADE_TYPE
.
TOKEN_TO_ETH
ensureTradeTypesMatch
(
computedTradeType
,
passedTradeType
)
return
{
tradeType
:
computedTradeType
,
inputReserves
:
normalizeTokenReserves
(
optionalReservesInput
),
outputReserves
:
{
token
:
ETH_TOKEN
(
areETHReserves
(
optionalReservesOutput
)
?
optionalReservesOutput
.
token
.
chainId
:
undefined
)
}
}
}
else
if
(
!
areTokenReserves
(
optionalReservesInput
)
&&
areTokenReserves
(
optionalReservesOutput
))
{
const
computedTradeType
:
TRADE_TYPE
=
TRADE_TYPE
.
ETH_TO_TOKEN
ensureTradeTypesMatch
(
computedTradeType
,
passedTradeType
)
return
{
tradeType
:
computedTradeType
,
inputReserves
:
{
token
:
ETH_TOKEN
(
areETHReserves
(
optionalReservesInput
)
?
optionalReservesInput
.
token
.
chainId
:
undefined
)
},
outputReserves
:
normalizeTokenReserves
(
optionalReservesOutput
)
}
}
else
{
throw
Error
(
'
optionalReservesInput, optionalReservesOutput, or both must be defined.
'
)
}
}
import
{
TokenAmountNormalized
,
_DecimalRate
,
_AnyRate
}
from
'
../types
'
import
{
_1
,
_10
}
from
'
../constants
'
export
function
calculateDecimalRate
(
numerator
:
TokenAmountNormalized
,
...
...
@@ -119,9 +34,3 @@ export function calculateDecimalRate(
.
dividedBy
(
decimalRate
.
numerator
)
}
}
// slippage in basis points, to 18 decimals
export
function
calculateSlippage
(
baseRate
:
BigNumber
,
newRate
:
BigNumber
):
BigNumber
{
const
difference
:
BigNumber
=
baseRate
.
minus
(
newRate
).
absoluteValue
()
return
difference
.
multipliedBy
(
_10000
).
dividedBy
(
baseRate
)
}
src/computation/market.ts
View file @
1fcc0a59
import
BigNumber
from
'
bignumber.js
'
import
{
TokenAmount
,
TokenAmountNormalized
,
Optional
Reserves
,
Token
Reserves
,
TokenReservesNormalized
,
NormalizedReserves
,
areTokenReservesNormalized
,
areETHReserves
,
areTokenReserves
,
OptionalReserves
,
NormalizedReserves
,
Rate
,
MarketDetails
,
_ParsedOptionalReserves
,
...
...
@@ -13,7 +17,67 @@ import {
_AnyRate
}
from
'
../types
'
import
{
TRADE_TYPE
}
from
'
../constants
'
import
{
parseOptionalReserves
,
calculateDecimalRate
}
from
'
./_utils
'
import
{
normalizeBigNumberish
,
ensureAllUInt8
,
ensureAllUInt256
}
from
'
../_utils
'
import
{
getEthToken
}
from
'
../data
'
import
{
calculateDecimalRate
}
from
'
./_utils
'
function
normalizeTokenAmount
(
tokenAmount
:
TokenAmount
):
TokenAmountNormalized
{
ensureAllUInt8
([
tokenAmount
.
token
.
decimals
])
const
normalizedAmount
:
BigNumber
=
normalizeBigNumberish
(
tokenAmount
.
amount
)
ensureAllUInt256
([
normalizedAmount
])
return
{
token
:
{
...
tokenAmount
.
token
},
amount
:
normalizedAmount
}
}
function
normalizeTokenReserves
(
tokenReserves
:
TokenReserves
):
TokenReservesNormalized
{
ensureAllUInt8
([
tokenReserves
.
token
.
decimals
])
return
{
token
:
{
...
tokenReserves
.
token
},
...(
tokenReserves
.
exchange
?
{
exchange
:
{
...
tokenReserves
.
exchange
}
}
:
{}),
ethReserve
:
normalizeTokenAmount
(
tokenReserves
.
ethReserve
),
tokenReserve
:
normalizeTokenAmount
(
tokenReserves
.
tokenReserve
)
}
}
function
parseOptionalReserves
(
optionalReservesInput
:
OptionalReserves
,
optionalReservesOutput
:
OptionalReserves
):
_ParsedOptionalReserves
{
if
(
areTokenReserves
(
optionalReservesInput
)
&&
areTokenReserves
(
optionalReservesOutput
))
{
return
{
tradeType
:
TRADE_TYPE
.
TOKEN_TO_TOKEN
,
inputReserves
:
normalizeTokenReserves
(
optionalReservesInput
),
outputReserves
:
normalizeTokenReserves
(
optionalReservesOutput
)
}
}
else
if
(
areTokenReserves
(
optionalReservesInput
)
&&
!
areTokenReserves
(
optionalReservesOutput
))
{
return
{
tradeType
:
TRADE_TYPE
.
TOKEN_TO_ETH
,
inputReserves
:
normalizeTokenReserves
(
optionalReservesInput
),
outputReserves
:
areETHReserves
(
optionalReservesOutput
)
?
optionalReservesOutput
:
{
token
:
getEthToken
(
optionalReservesInput
.
token
.
chainId
)
}
}
}
else
if
(
!
areTokenReserves
(
optionalReservesInput
)
&&
areTokenReserves
(
optionalReservesOutput
))
{
return
{
tradeType
:
TRADE_TYPE
.
ETH_TO_TOKEN
,
inputReserves
:
areETHReserves
(
optionalReservesInput
)
?
optionalReservesInput
:
{
token
:
getEthToken
(
optionalReservesOutput
.
token
.
chainId
)
},
outputReserves
:
normalizeTokenReserves
(
optionalReservesOutput
)
}
}
else
{
throw
Error
(
'
optionalReservesInput, optionalReservesOutput, or both must be defined.
'
)
}
}
// calculates the market rate for ETH_TO_TOKEN or TOKEN_TO_ETH trades
function
getMarketRate
(
tradeType
:
TRADE_TYPE
,
reserves
:
NormalizedReserves
,
keepAsDecimal
?:
boolean
):
_AnyRate
{
...
...
@@ -31,14 +95,12 @@ function getMarketRate(tradeType: TRADE_TYPE, reserves: NormalizedReserves, keep
// note: rounds rates to 18 decimal places
export
function
getMarketDetails
(
tradeType
:
TRADE_TYPE
,
optionalReservesInput
:
OptionalReserves
,
optionalReservesOutput
:
OptionalReserves
):
MarketDetails
{
const
{
inputReserves
,
outputReserves
}:
_ParsedOptionalReserves
=
parseOptionalReserves
(
const
{
tradeType
,
inputReserves
,
outputReserves
}:
_ParsedOptionalReserves
=
parseOptionalReserves
(
optionalReservesInput
,
optionalReservesOutput
,
tradeType
optionalReservesOutput
)
if
(
tradeType
===
TRADE_TYPE
.
TOKEN_TO_TOKEN
)
{
...
...
src/computation/trade.ts
View file @
1fcc0a59
...
...
@@ -3,19 +3,20 @@ import cloneDeepWith from 'lodash.clonedeepwith'
import
{
BigNumberish
,
Rate
,
MarketDetails
,
TradeDetails
,
TokenAmountNormalized
,
areTokenReservesNormalized
,
NormalizedReserves
,
Rate
,
MarketDetails
,
TradeDetails
,
_PartialTradeDetails
}
from
'
../types
'
import
{
_0
,
_1
,
_997
,
_1000
,
TRADE_TYPE
,
TRADE_EXACT
}
from
'
../constants
'
import
{
ensureAllUInt256
,
normalizeBigNumberish
}
from
'
../_utils
'
import
{
calculateDecimalRate
,
calculateSlippage
}
from
'
./_utils
'
import
{
_0
,
_1
,
_997
,
_1000
,
TRADE_TYPE
,
TRADE_EXACT
,
_10000
}
from
'
../constants
'
import
{
normalizeBigNumberish
,
ensureAllUInt256
}
from
'
../_utils
'
import
{
calculateDecimalRate
}
from
'
./_utils
'
import
{
getMarketDetails
}
from
'
./market
'
// emulates the uniswap smart contract logic
function
getInputPrice
(
inputAmount
:
BigNumber
,
inputReserve
:
BigNumber
,
outputReserve
:
BigNumber
):
BigNumber
{
ensureAllUInt256
([
inputAmount
,
inputReserve
,
outputReserve
])
...
...
@@ -33,6 +34,7 @@ function getInputPrice(inputAmount: BigNumber, inputReserve: BigNumber, outputRe
return
outputAmount
}
// emulates the uniswap smart contract logic
function
getOutputPrice
(
outputAmount
:
BigNumber
,
inputReserve
:
BigNumber
,
outputReserve
:
BigNumber
):
BigNumber
{
ensureAllUInt256
([
outputAmount
,
inputReserve
,
outputReserve
])
...
...
@@ -49,7 +51,7 @@ function getOutputPrice(outputAmount: BigNumber, inputReserve: BigNumber, output
return
inputAmount
}
function
_get
TradeTransput
(
function
getSingle
TradeTransput
(
tradeType
:
TRADE_TYPE
,
tradeExact
:
TRADE_EXACT
,
tradeAmount
:
BigNumber
,
...
...
@@ -72,11 +74,10 @@ function _getTradeTransput(
return
calculatedAmount
}
function
customizer
(
value
:
BigNumber
):
BigNumber
|
undefine
d
{
function
customizer
(
value
:
BigNumber
):
BigNumber
|
voi
d
{
if
(
BigNumber
.
isBigNumber
(
value
))
{
return
new
BigNumber
(
value
)
}
return
}
// gets the corresponding input/output amount for the passed output/input amount
...
...
@@ -96,13 +97,13 @@ function getTradeTransput(
}
if
(
tradeExact
===
TRADE_EXACT
.
INPUT
)
{
const
intermediateTransput
:
BigNumber
=
_get
TradeTransput
(
const
intermediateTransput
:
BigNumber
=
getSingle
TradeTransput
(
TRADE_TYPE
.
TOKEN_TO_ETH
,
TRADE_EXACT
.
INPUT
,
tradeAmount
,
inputReserves
)
const
finalTransput
:
BigNumber
=
_get
TradeTransput
(
const
finalTransput
:
BigNumber
=
getSingle
TradeTransput
(
TRADE_TYPE
.
ETH_TO_TOKEN
,
TRADE_EXACT
.
INPUT
,
intermediateTransput
,
...
...
@@ -120,13 +121,13 @@ function getTradeTransput(
outputReservesPost
}
}
else
{
const
intermediateTransput
:
BigNumber
=
_get
TradeTransput
(
const
intermediateTransput
:
BigNumber
=
getSingle
TradeTransput
(
TRADE_TYPE
.
ETH_TO_TOKEN
,
TRADE_EXACT
.
OUTPUT
,
tradeAmount
,
outputReserves
)
const
finalTransput
:
BigNumber
=
_get
TradeTransput
(
const
finalTransput
:
BigNumber
=
getSingle
TradeTransput
(
TRADE_TYPE
.
TOKEN_TO_ETH
,
TRADE_EXACT
.
OUTPUT
,
intermediateTransput
,
...
...
@@ -147,7 +148,7 @@ function getTradeTransput(
}
else
{
const
reserves
:
NormalizedReserves
=
tradeType
===
TRADE_TYPE
.
ETH_TO_TOKEN
?
outputReserves
:
inputReserves
const
finalTransput
:
BigNumber
=
_get
TradeTransput
(
tradeType
,
tradeExact
,
tradeAmount
,
reserves
)
const
finalTransput
:
BigNumber
=
getSingle
TradeTransput
(
tradeType
,
tradeExact
,
tradeAmount
,
reserves
)
if
(
tradeType
===
TRADE_TYPE
.
ETH_TO_TOKEN
)
{
if
(
!
areTokenReservesNormalized
(
outputReservesPost
))
{
...
...
@@ -181,13 +182,20 @@ function getTradeTransput(
}
}
// slippage in basis points, to 18 decimals
function
calculateSlippage
(
baseRate
:
BigNumber
,
newRate
:
BigNumber
):
BigNumber
{
const
difference
:
BigNumber
=
baseRate
.
minus
(
newRate
).
absoluteValue
()
return
difference
.
multipliedBy
(
_10000
).
dividedBy
(
baseRate
)
}
export
function
getTradeDetails
(
tradeExact
:
TRADE_EXACT
,
_tradeAmount
:
BigNumberish
,
marketDetails
:
MarketDetails
):
TradeDetails
{
// get other input/output amount
const
tradeAmount
:
BigNumber
=
normalizeBigNumberish
(
_tradeAmount
)
// get other input/output amount
const
{
transput
,
inputReservesPost
,
outputReservesPost
}:
_PartialTradeDetails
=
getTradeTransput
(
marketDetails
.
tradeType
,
tradeExact
,
...
...
@@ -206,11 +214,7 @@ export function getTradeDetails(
amount
:
tradeExact
===
TRADE_EXACT
.
INPUT
?
transput
:
tradeAmount
}
const
marketDetailsPost
:
MarketDetails
=
getMarketDetails
(
marketDetails
.
tradeType
,
inputReservesPost
,
outputReservesPost
)
const
marketDetailsPost
:
MarketDetails
=
getMarketDetails
(
inputReservesPost
,
outputReservesPost
)
const
executionRate
:
Rate
=
calculateDecimalRate
(
outputAmount
,
inputAmount
)
as
Rate
...
...
src/constants/abis/ERC20.json
View file @
1fcc0a59
...
...
@@ -3,16 +3,31 @@
"constant"
:
true
,
"inputs"
:
[],
"name"
:
"decimals"
,
"outputs"
:
[{
"name"
:
"", "type"
:
"uint8"
}],
"outputs"
:
[
{
"name"
:
""
,
"type"
:
"uint8"
}
],
"payable"
:
false
,
"stateMutability"
:
"view"
,
"type"
:
"function"
},
{
"constant"
:
true
,
"inputs"
:
[{
"name"
:
"", "type"
:
"address"
}],
"inputs"
:
[
{
"name"
:
""
,
"type"
:
"address"
}
],
"name"
:
"balanceOf"
,
"outputs"
:
[{
"name"
:
"", "type"
:
"uint256"
}],
"outputs"
:
[
{
"name"
:
""
,
"type"
:
"uint256"
}
],
"payable"
:
false
,
"stateMutability"
:
"view"
,
"type"
:
"function"
...
...
src/constants/abis/EXCHANGE.json
0 → 100644
View file @
1fcc0a59
[
{
"name"
:
"TokenPurchase"
,
"inputs"
:
[
{
"type"
:
"address", "name"
:
"buyer", "indexed"
:
true
},
{
"type"
:
"uint256", "name"
:
"eth_sold", "indexed"
:
true
},
{
"type"
:
"uint256", "name"
:
"tokens_bought", "indexed"
:
true
}
],
"anonymous"
:
false
,
"type"
:
"event"
},
{
"name"
:
"EthPurchase"
,
"inputs"
:
[
{
"type"
:
"address", "name"
:
"buyer", "indexed"
:
true
},
{
"type"
:
"uint256", "name"
:
"tokens_sold", "indexed"
:
true
},
{
"type"
:
"uint256", "name"
:
"eth_bought", "indexed"
:
true
}
],
"anonymous"
:
false
,
"type"
:
"event"
},
{
"name"
:
"AddLiquidity"
,
"inputs"
:
[
{
"type"
:
"address", "name"
:
"provider", "indexed"
:
true
},
{
"type"
:
"uint256", "name"
:
"eth_amount", "indexed"
:
true
},
{
"type"
:
"uint256", "name"
:
"token_amount", "indexed"
:
true
}
],
"anonymous"
:
false
,
"type"
:
"event"
},
{
"name"
:
"RemoveLiquidity"
,
"inputs"
:
[
{
"type"
:
"address", "name"
:
"provider", "indexed"
:
true
},
{
"type"
:
"uint256", "name"
:
"eth_amount", "indexed"
:
true
},
{
"type"
:
"uint256", "name"
:
"token_amount", "indexed"
:
true
}
],
"anonymous"
:
false
,
"type"
:
"event"
},
{
"name"
:
"Transfer"
,
"inputs"
:
[
{
"type"
:
"address", "name"
:
"_from", "indexed"
:
true
},
{
"type"
:
"address", "name"
:
"_to", "indexed"
:
true
},
{
"type"
:
"uint256", "name"
:
"_value", "indexed"
:
false
}
],
"anonymous"
:
false
,
"type"
:
"event"
},
{
"name"
:
"Approval"
,
"inputs"
:
[
{
"type"
:
"address", "name"
:
"_owner", "indexed"
:
true
},
{
"type"
:
"address", "name"
:
"_spender", "indexed"
:
true
},
{
"type"
:
"uint256", "name"
:
"_value", "indexed"
:
false
}
],
"anonymous"
:
false
,
"type"
:
"event"
},
{
"name"
:
"setup"
,
"outputs"
:
[],
"inputs"
:
[{
"type"
:
"address", "name"
:
"token_addr"
}],
"constant"
:
false
,
"payable"
:
false
,
"type"
:
"function"
,
"gas"
:
175875
},
{
"name"
:
"addLiquidity"
,
"outputs"
:
[{
"type"
:
"uint256", "name"
:
"out"
}],
"inputs"
:
[
{
"type"
:
"uint256", "name"
:
"min_liquidity"
},
{
"type"
:
"uint256", "name"
:
"max_tokens"
},
{
"type"
:
"uint256", "name"
:
"deadline"
}
],
"constant"
:
false
,
"payable"
:
true
,
"type"
:
"function"
,
"gas"
:
82616
},
{
"name"
:
"removeLiquidity"
,
"outputs"
:
[{
"type"
:
"uint256", "name"
:
"out" }, { "type"
:
"uint256", "name"
:
"out"
}],
"inputs"
:
[
{
"type"
:
"uint256", "name"
:
"amount"
},
{
"type"
:
"uint256", "name"
:
"min_eth"
},
{
"type"
:
"uint256", "name"
:
"min_tokens"
},
{
"type"
:
"uint256", "name"
:
"deadline"
}
],
"constant"
:
false
,
"payable"
:
false
,
"type"
:
"function"
,
"gas"
:
116814
},
{
"name"
:
"__default__", "outputs"
:
[],
"inputs"
:
[],
"constant"
:
false
,
"payable"
:
true
,
"type"
:
"function"
},
{
"name"
:
"ethToTokenSwapInput"
,
"outputs"
:
[{
"type"
:
"uint256", "name"
:
"out"
}],
"inputs"
:
[{
"type"
:
"uint256", "name"
:
"min_tokens" }, { "type"
:
"uint256", "name"
:
"deadline"
}],
"constant"
:
false
,
"payable"
:
true
,
"type"
:
"function"
,
"gas"
:
12757
},
{
"name"
:
"ethToTokenTransferInput"
,
"outputs"
:
[{
"type"
:
"uint256", "name"
:
"out"
}],
"inputs"
:
[
{
"type"
:
"uint256", "name"
:
"min_tokens"
},
{
"type"
:
"uint256", "name"
:
"deadline"
},
{
"type"
:
"address", "name"
:
"recipient"
}
],
"constant"
:
false
,
"payable"
:
true
,
"type"
:
"function"
,
"gas"
:
12965
},
{
"name"
:
"ethToTokenSwapOutput"
,
"outputs"
:
[{
"type"
:
"uint256", "name"
:
"out"
}],
"inputs"
:
[{
"type"
:
"uint256", "name"
:
"tokens_bought" }, { "type"
:
"uint256", "name"
:
"deadline"
}],
"constant"
:
false
,
"payable"
:
true
,
"type"
:
"function"
,
"gas"
:
50463
},
{
"name"
:
"ethToTokenTransferOutput"
,
"outputs"
:
[{
"type"
:
"uint256", "name"
:
"out"
}],
"inputs"
:
[
{
"type"
:
"uint256", "name"
:
"tokens_bought"
},
{
"type"
:
"uint256", "name"
:
"deadline"
},
{
"type"
:
"address", "name"
:
"recipient"
}
],
"constant"
:
false
,
"payable"
:
true
,
"type"
:
"function"
,
"gas"
:
50671
},
{
"name"
:
"tokenToEthSwapInput"
,
"outputs"
:
[{
"type"
:
"uint256", "name"
:
"out"
}],
"inputs"
:
[
{
"type"
:
"uint256", "name"
:
"tokens_sold"
},
{
"type"
:
"uint256", "name"
:
"min_eth"
},
{
"type"
:
"uint256", "name"
:
"deadline"
}
],
"constant"
:
false
,
"payable"
:
false
,
"type"
:
"function"
,
"gas"
:
47503
},
{
"name"
:
"tokenToEthTransferInput"
,
"outputs"
:
[{
"type"
:
"uint256", "name"
:
"out"
}],
"inputs"
:
[
{
"type"
:
"uint256", "name"
:
"tokens_sold"
},
{
"type"
:
"uint256", "name"
:
"min_eth"
},
{
"type"
:
"uint256", "name"
:
"deadline"
},
{
"type"
:
"address", "name"
:
"recipient"
}
],
"constant"
:
false
,
"payable"
:
false
,
"type"
:
"function"
,
"gas"
:
47712
},
{
"name"
:
"tokenToEthSwapOutput"
,
"outputs"
:
[{
"type"
:
"uint256", "name"
:
"out"
}],
"inputs"
:
[
{
"type"
:
"uint256", "name"
:
"eth_bought"
},
{
"type"
:
"uint256", "name"
:
"max_tokens"
},
{
"type"
:
"uint256", "name"
:
"deadline"
}
],
"constant"
:
false
,
"payable"
:
false
,
"type"
:
"function"
,
"gas"
:
50175
},
{
"name"
:
"tokenToEthTransferOutput"
,
"outputs"
:
[{
"type"
:
"uint256", "name"
:
"out"
}],
"inputs"
:
[
{
"type"
:
"uint256", "name"
:
"eth_bought"
},
{
"type"
:
"uint256", "name"
:
"max_tokens"
},
{
"type"
:
"uint256", "name"
:
"deadline"
},
{
"type"
:
"address", "name"
:
"recipient"
}
],
"constant"
:
false
,
"payable"
:
false
,
"type"
:
"function"
,
"gas"
:
50384
},
{
"name"
:
"tokenToTokenSwapInput"
,
"outputs"
:
[{
"type"
:
"uint256", "name"
:
"out"
}],
"inputs"
:
[
{
"type"
:
"uint256", "name"
:
"tokens_sold"
},
{
"type"
:
"uint256", "name"
:
"min_tokens_bought"
},
{
"type"
:
"uint256", "name"
:
"min_eth_bought"
},
{
"type"
:
"uint256", "name"
:
"deadline"
},
{
"type"
:
"address", "name"
:
"token_addr"
}
],
"constant"
:
false
,
"payable"
:
false
,
"type"
:
"function"
,
"gas"
:
51007
},
{
"name"
:
"tokenToTokenTransferInput"
,
"outputs"
:
[{
"type"
:
"uint256", "name"
:
"out"
}],
"inputs"
:
[
{
"type"
:
"uint256", "name"
:
"tokens_sold"
},
{
"type"
:
"uint256", "name"
:
"min_tokens_bought"
},
{
"type"
:
"uint256", "name"
:
"min_eth_bought"
},
{
"type"
:
"uint256", "name"
:
"deadline"
},
{
"type"
:
"address", "name"
:
"recipient"
},
{
"type"
:
"address", "name"
:
"token_addr"
}
],
"constant"
:
false
,
"payable"
:
false
,
"type"
:
"function"
,
"gas"
:
51098
},
{
"name"
:
"tokenToTokenSwapOutput"
,
"outputs"
:
[{
"type"
:
"uint256", "name"
:
"out"
}],
"inputs"
:
[
{
"type"
:
"uint256", "name"
:
"tokens_bought"
},
{
"type"
:
"uint256", "name"
:
"max_tokens_sold"
},
{
"type"
:
"uint256", "name"
:
"max_eth_sold"
},
{
"type"
:
"uint256", "name"
:
"deadline"
},
{
"type"
:
"address", "name"
:
"token_addr"
}
],
"constant"
:
false
,
"payable"
:
false
,
"type"
:
"function"
,
"gas"
:
54928
},
{
"name"
:
"tokenToTokenTransferOutput"
,
"outputs"
:
[{
"type"
:
"uint256", "name"
:
"out"
}],
"inputs"
:
[
{
"type"
:
"uint256", "name"
:
"tokens_bought"
},
{
"type"
:
"uint256", "name"
:
"max_tokens_sold"
},
{
"type"
:
"uint256", "name"
:
"max_eth_sold"
},
{
"type"
:
"uint256", "name"
:
"deadline"
},
{
"type"
:
"address", "name"
:
"recipient"
},
{
"type"
:
"address", "name"
:
"token_addr"
}
],
"constant"
:
false
,
"payable"
:
false
,
"type"
:
"function"
,
"gas"
:
55019
},
{
"name"
:
"tokenToExchangeSwapInput"
,
"outputs"
:
[{
"type"
:
"uint256", "name"
:
"out"
}],
"inputs"
:
[
{
"type"
:
"uint256", "name"
:
"tokens_sold"
},
{
"type"
:
"uint256", "name"
:
"min_tokens_bought"
},
{
"type"
:
"uint256", "name"
:
"min_eth_bought"
},
{
"type"
:
"uint256", "name"
:
"deadline"
},
{
"type"
:
"address", "name"
:
"exchange_addr"
}
],
"constant"
:
false
,
"payable"
:
false
,
"type"
:
"function"
,
"gas"
:
49342
},
{
"name"
:
"tokenToExchangeTransferInput"
,
"outputs"
:
[{
"type"
:
"uint256", "name"
:
"out"
}],
"inputs"
:
[
{
"type"
:
"uint256", "name"
:
"tokens_sold"
},
{
"type"
:
"uint256", "name"
:
"min_tokens_bought"
},
{
"type"
:
"uint256", "name"
:
"min_eth_bought"
},
{
"type"
:
"uint256", "name"
:
"deadline"
},
{
"type"
:
"address", "name"
:
"recipient"
},
{
"type"
:
"address", "name"
:
"exchange_addr"
}
],
"constant"
:
false
,
"payable"
:
false
,
"type"
:
"function"
,
"gas"
:
49532
},
{
"name"
:
"tokenToExchangeSwapOutput"
,
"outputs"
:
[{
"type"
:
"uint256", "name"
:
"out"
}],
"inputs"
:
[
{
"type"
:
"uint256", "name"
:
"tokens_bought"
},
{
"type"
:
"uint256", "name"
:
"max_tokens_sold"
},
{
"type"
:
"uint256", "name"
:
"max_eth_sold"
},
{
"type"
:
"uint256", "name"
:
"deadline"
},
{
"type"
:
"address", "name"
:
"exchange_addr"
}
],
"constant"
:
false
,
"payable"
:
false
,
"type"
:
"function"
,
"gas"
:
53233
},
{
"name"
:
"tokenToExchangeTransferOutput"
,
"outputs"
:
[{
"type"
:
"uint256", "name"
:
"out"
}],
"inputs"
:
[
{
"type"
:
"uint256", "name"
:
"tokens_bought"
},
{
"type"
:
"uint256", "name"
:
"max_tokens_sold"
},
{
"type"
:
"uint256", "name"
:
"max_eth_sold"
},
{
"type"
:
"uint256", "name"
:
"deadline"
},
{
"type"
:
"address", "name"
:
"recipient"
},
{
"type"
:
"address", "name"
:
"exchange_addr"
}
],
"constant"
:
false
,
"payable"
:
false
,
"type"
:
"function"
,
"gas"
:
53423
},
{
"name"
:
"getEthToTokenInputPrice"
,
"outputs"
:
[{
"type"
:
"uint256", "name"
:
"out"
}],
"inputs"
:
[{
"type"
:
"uint256", "name"
:
"eth_sold"
}],
"constant"
:
true
,
"payable"
:
false
,
"type"
:
"function"
,
"gas"
:
5542
},
{
"name"
:
"getEthToTokenOutputPrice"
,
"outputs"
:
[{
"type"
:
"uint256", "name"
:
"out"
}],
"inputs"
:
[{
"type"
:
"uint256", "name"
:
"tokens_bought"
}],
"constant"
:
true
,
"payable"
:
false
,
"type"
:
"function"
,
"gas"
:
6872
},
{
"name"
:
"getTokenToEthInputPrice"
,
"outputs"
:
[{
"type"
:
"uint256", "name"
:
"out"
}],
"inputs"
:
[{
"type"
:
"uint256", "name"
:
"tokens_sold"
}],
"constant"
:
true
,
"payable"
:
false
,
"type"
:
"function"
,
"gas"
:
5637
},
{
"name"
:
"getTokenToEthOutputPrice"
,
"outputs"
:
[{
"type"
:
"uint256", "name"
:
"out"
}],
"inputs"
:
[{
"type"
:
"uint256", "name"
:
"eth_bought"
}],
"constant"
:
true
,
"payable"
:
false
,
"type"
:
"function"
,
"gas"
:
6897
},
{
"name"
:
"tokenAddress"
,
"outputs"
:
[{
"type"
:
"address", "name"
:
"out"
}],
"inputs"
:
[],
"constant"
:
true
,
"payable"
:
false
,
"type"
:
"function"
,
"gas"
:
1413
},
{
"name"
:
"factoryAddress"
,
"outputs"
:
[{
"type"
:
"address", "name"
:
"out"
}],
"inputs"
:
[],
"constant"
:
true
,
"payable"
:
false
,
"type"
:
"function"
,
"gas"
:
1443
},
{
"name"
:
"balanceOf"
,
"outputs"
:
[{
"type"
:
"uint256", "name"
:
"out"
}],
"inputs"
:
[{
"type"
:
"address", "name"
:
"_owner"
}],
"constant"
:
true
,
"payable"
:
false
,
"type"
:
"function"
,
"gas"
:
1645
},
{
"name"
:
"transfer"
,
"outputs"
:
[{
"type"
:
"bool", "name"
:
"out"
}],
"inputs"
:
[{
"type"
:
"address", "name"
:
"_to" }, { "type"
:
"uint256", "name"
:
"_value"
}],
"constant"
:
false
,
"payable"
:
false
,
"type"
:
"function"
,
"gas"
:
75034
},
{
"name"
:
"transferFrom"
,
"outputs"
:
[{
"type"
:
"bool", "name"
:
"out"
}],
"inputs"
:
[
{
"type"
:
"address", "name"
:
"_from"
},
{
"type"
:
"address", "name"
:
"_to"
},
{
"type"
:
"uint256", "name"
:
"_value"
}
],
"constant"
:
false
,
"payable"
:
false
,
"type"
:
"function"
,
"gas"
:
110907
},
{
"name"
:
"approve"
,
"outputs"
:
[{
"type"
:
"bool", "name"
:
"out"
}],
"inputs"
:
[{
"type"
:
"address", "name"
:
"_spender" }, { "type"
:
"uint256", "name"
:
"_value"
}],
"constant"
:
false
,
"payable"
:
false
,
"type"
:
"function"
,
"gas"
:
38769
},
{
"name"
:
"allowance"
,
"outputs"
:
[{
"type"
:
"uint256", "name"
:
"out"
}],
"inputs"
:
[{
"type"
:
"address", "name"
:
"_owner" }, { "type"
:
"address", "name"
:
"_spender"
}],
"constant"
:
true
,
"payable"
:
false
,
"type"
:
"function"
,
"gas"
:
1925
},
{
"name"
:
"name"
,
"outputs"
:
[{
"type"
:
"bytes32", "name"
:
"out"
}],
"inputs"
:
[],
"constant"
:
true
,
"payable"
:
false
,
"type"
:
"function"
,
"gas"
:
1623
},
{
"name"
:
"symbol"
,
"outputs"
:
[{
"type"
:
"bytes32", "name"
:
"out"
}],
"inputs"
:
[],
"constant"
:
true
,
"payable"
:
false
,
"type"
:
"function"
,
"gas"
:
1653
},
{
"name"
:
"decimals"
,
"outputs"
:
[{
"type"
:
"uint256", "name"
:
"out"
}],
"inputs"
:
[],
"constant"
:
true
,
"payable"
:
false
,
"type"
:
"function"
,
"gas"
:
1683
},
{
"name"
:
"totalSupply"
,
"outputs"
:
[{
"type"
:
"uint256", "name"
:
"out"
}],
"inputs"
:
[],
"constant"
:
true
,
"payable"
:
false
,
"type"
:
"function"
,
"gas"
:
1713
}
]
src/constants/abis/FACTORY.json
View file @
1fcc0a59
[
{
"constant"
:
true
,
"inputs"
:
[{
"name"
:
"token", "type"
:
"address"
}],
"name"
:
"NewExchange"
,
"inputs"
:
[
{
"type"
:
"address", "name"
:
"token", "indexed"
:
true
},
{
"type"
:
"address", "name"
:
"exchange", "indexed"
:
true
}
],
"anonymous"
:
false
,
"type"
:
"event"
},
{
"name"
:
"initializeFactory"
,
"outputs"
:
[],
"inputs"
:
[{
"type"
:
"address", "name"
:
"template"
}],
"constant"
:
false
,
"payable"
:
false
,
"type"
:
"function"
,
"gas"
:
35725
},
{
"name"
:
"createExchange"
,
"outputs"
:
[{
"type"
:
"address", "name"
:
"out"
}],
"inputs"
:
[{
"type"
:
"address", "name"
:
"token"
}],
"constant"
:
false
,
"payable"
:
false
,
"type"
:
"function"
,
"gas"
:
187911
},
{
"name"
:
"getExchange"
,
"outputs"
:
[{
"name"
:
"", "type"
:
"address"
}],
"outputs"
:
[{
"type"
:
"address", "name"
:
"out"
}],
"inputs"
:
[{
"type"
:
"address", "name"
:
"token"
}],
"constant"
:
true
,
"payable"
:
false
,
"type"
:
"function"
,
"gas"
:
715
},
{
"name"
:
"getToken"
,
"outputs"
:
[{
"type"
:
"address", "name"
:
"out"
}],
"inputs"
:
[{
"type"
:
"address", "name"
:
"exchange"
}],
"constant"
:
true
,
"payable"
:
false
,
"type"
:
"function"
,
"gas"
:
745
},
{
"name"
:
"getTokenWithId"
,
"outputs"
:
[{
"type"
:
"address", "name"
:
"out"
}],
"inputs"
:
[{
"type"
:
"uint256", "name"
:
"token_id"
}],
"constant"
:
true
,
"payable"
:
false
,
"type"
:
"function"
,
"gas"
:
736
},
{
"name"
:
"exchangeTemplate"
,
"outputs"
:
[{
"type"
:
"address", "name"
:
"out"
}],
"inputs"
:
[],
"constant"
:
true
,
"payable"
:
false
,
"type"
:
"function"
,
"gas"
:
633
},
{
"name"
:
"tokenCount"
,
"outputs"
:
[{
"type"
:
"uint256", "name"
:
"out"
}],
"inputs"
:
[],
"constant"
:
true
,
"payable"
:
false
,
"
stateMutability"
:
"view
"
,
"
type"
:
"function"
"
type"
:
"function
"
,
"
gas"
:
663
}
]
src/constants/index.ts
View file @
1fcc0a59
import
BigNumber
from
'
bignumber.js
'
import
{
Token
}
from
'
../types
'
import
ERC20
from
'
./abis/ERC20.json
'
import
FACTORY
from
'
./abis/FACTORY.json
'
import
EXCHANGE
from
'
./abis/EXCHANGE.json
'
//// constants for internal and external use
export
const
ETH
=
'
ETH
'
...
...
@@ -21,9 +21,12 @@ export const FACTORY_ADDRESS: { [key: number]: string } = {
[
SUPPORTED_CHAIN_ID
.
Kovan
]:
'
0xD3E51Ef092B2845f10401a0159B2B96e8B6c3D30
'
}
export
const
FACTORY_ABI
:
string
=
JSON
.
stringify
(
FACTORY
)
export
const
EXCHANGE_ABI
:
string
=
JSON
.
stringify
(
EXCHANGE
)
export
enum
TRADE_TYPE
{
TOKEN_TO_ETH
=
'
TOKEN_TO_ETH
'
,
ETH_TO_TOKEN
=
'
ETH_TO_TOKEN
'
,
TOKEN_TO_ETH
=
'
TOKEN_TO_ETH
'
,
TOKEN_TO_TOKEN
=
'
TOKEN_TO_TOKEN
'
}
...
...
@@ -32,6 +35,36 @@ export enum TRADE_EXACT {
OUTPUT
=
'
OUTPUT
'
}
export
enum
TRADE_METHODS
{
ethToTokenSwapInput
=
'
ethToTokenSwapInput
'
,
ethToTokenTransferInput
=
'
ethToTokenTransferInput
'
,
ethToTokenSwapOutput
=
'
ethToTokenSwapOutput
'
,
ethToTokenTransferOutput
=
'
ethToTokenTransferOutput
'
,
tokenToEthSwapInput
=
'
tokenToEthSwapInput
'
,
tokenToEthTransferInput
=
'
tokenToEthTransferInput
'
,
tokenToEthSwapOutput
=
'
tokenToEthSwapOutput
'
,
tokenToEthTransferOutput
=
'
tokenToEthTransferOutput
'
,
tokenToTokenSwapInput
=
'
tokenToTokenSwapInput
'
,
tokenToTokenTransferInput
=
'
tokenToTokenTransferInput
'
,
tokenToTokenSwapOutput
=
'
tokenToTokenSwapOutput
'
,
tokenToTokenTransferOutput
=
'
tokenToTokenTransferOutput
'
}
export
const
TRADE_METHOD_IDS
:
{
[
key
:
string
]:
string
}
=
{
[
TRADE_METHODS
.
ethToTokenSwapInput
]:
'
0xf39b5b9b
'
,
[
TRADE_METHODS
.
ethToTokenTransferInput
]:
'
0xad65d76d
'
,
[
TRADE_METHODS
.
ethToTokenSwapOutput
]:
'
0x6b1d4db7
'
,
[
TRADE_METHODS
.
ethToTokenTransferOutput
]:
'
0x0b573638
'
,
[
TRADE_METHODS
.
tokenToEthSwapInput
]:
'
0x95e3c50b
'
,
[
TRADE_METHODS
.
tokenToEthTransferInput
]:
'
0x7237e031
'
,
[
TRADE_METHODS
.
tokenToEthSwapOutput
]:
'
0x013efd8b
'
,
[
TRADE_METHODS
.
tokenToEthTransferOutput
]:
'
0xd4e4841d
'
,
[
TRADE_METHODS
.
tokenToTokenSwapInput
]:
'
0xddf7e1a7
'
,
[
TRADE_METHODS
.
tokenToTokenTransferInput
]:
'
0xf552d91b
'
,
[
TRADE_METHODS
.
tokenToTokenSwapOutput
]:
'
0xb040d545
'
,
[
TRADE_METHODS
.
tokenToTokenTransferOutput
]:
'
0xf3c0efe9
'
}
export
enum
FIXED_UNDERFLOW_BEHAVIOR
{
ZERO
=
'
ZERO
'
,
LESS_THAN
=
'
LESS_THAN
'
,
...
...
@@ -39,9 +72,9 @@ export enum FIXED_UNDERFLOW_BEHAVIOR {
}
//// constants for internal use
export
const
MAX_DECIMAL_PLACES
=
18
export
const
ROUNDING_MODE
=
BigNumber
.
ROUND_HALF_UP
BigNumber
.
set
({
DECIMAL_PLACES
:
MAX_DECIMAL_PLACES
,
ROUNDING_MODE
})
export
const
_
MAX_DECIMAL_PLACES
=
18
export
const
_
ROUNDING_MODE
=
BigNumber
.
ROUND_HALF_UP
BigNumber
.
set
({
DECIMAL_PLACES
:
_MAX_DECIMAL_PLACES
,
ROUNDING_MODE
:
_
ROUNDING_MODE
})
export
const
_0
:
BigNumber
=
new
BigNumber
(
'
0
'
)
export
const
_1
:
BigNumber
=
new
BigNumber
(
'
1
'
)
...
...
@@ -49,23 +82,16 @@ export const _10: BigNumber = new BigNumber('10')
export
const
_997
:
BigNumber
=
new
BigNumber
(
'
997
'
)
export
const
_1000
:
BigNumber
=
new
BigNumber
(
'
1000
'
)
export
const
_10000
:
BigNumber
=
new
BigNumber
(
'
10000
'
)
export
const
MAX_UINT8
:
number
=
2
**
8
-
1
export
const
MAX_UINT256
:
BigNumber
=
new
BigNumber
(
'
2
'
).
exponentiatedBy
(
new
BigNumber
(
'
256
'
)).
minus
(
_1
)
export
const
_MAX_UINT8
=
255
export
const
_MAX_UINT256
:
BigNumber
=
new
BigNumber
(
'
0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
'
)
export
function
ETH_TOKEN
(
chainId
?:
number
):
Token
{
return
{
...(
chainId
?
{
chainId
}
:
{}),
address
:
ETH
,
decimals
:
18
}
}
export
const
CHAIN_ID_NAME
:
{
[
key
:
number
]:
string
}
=
{
export
const
_CHAIN_ID_NAME
:
{
[
key
:
number
]:
string
}
=
{
[
SUPPORTED_CHAIN_ID
.
Mainnet
]:
'
homestead
'
,
[
SUPPORTED_CHAIN_ID
.
Ropsten
]:
'
ropsten
'
,
[
SUPPORTED_CHAIN_ID
.
Rinkeby
]:
'
rinkeby
'
,
[
SUPPORTED_CHAIN_ID
.
Kovan
]:
'
kovan
'
}
export
const
ERC20_ABI
:
string
=
JSON
.
stringify
(
ERC20
)
export
const
FACTORY_ABI
:
string
=
JSON
.
stringify
(
FACTORY
)
export
const
_ERC20_ABI
:
string
=
JSON
.
stringify
(
ERC20
)
src/data/index.ts
View file @
1fcc0a59
import
{
ethers
}
from
'
ethers
'
import
{
ETH
,
ETH_TOKEN
,
CHAIN_ID_NAME
,
ERC20_ABI
,
FACTORY_ADDRESS
,
FACTORY_ABI
}
from
'
../constant
s
'
import
{
ChainIdOrProvider
,
isChainId
,
_ChainIdAndProvider
,
Token
,
TokenReservesNormalized
}
from
'
../type
s
'
import
{
normalize
Address
,
normalizeBigNumberish
}
from
'
../_utils
'
import
{
ChainIdOrProvider
,
isChainId
,
Token
,
TokenReservesNormalized
,
_ChainIdAndProvider
}
from
'
../type
s
'
import
{
ETH
,
SUPPORTED_CHAIN_ID
,
FACTORY_ABI
,
FACTORY_ADDRESS
,
_CHAIN_ID_NAME
,
_ERC20_ABI
}
from
'
../constant
s
'
import
{
normalize
BigNumberish
,
normalizeAddress
}
from
'
../_utils
'
// get contract object with address, ABI, and provider
function
_getContract
(
address
:
string
,
ABI
:
string
,
provider
:
ethers
.
providers
.
BaseProvider
):
ethers
.
Contract
{
return
new
ethers
.
Contract
(
normalizeAddress
(
address
),
ABI
,
provider
)
function
getContract
(
address
:
string
,
ABI
:
string
,
provider
:
ethers
.
providers
.
BaseProvider
):
ethers
.
Contract
{
return
new
ethers
.
Contract
(
address
,
ABI
,
provider
)
}
// get chain id and provider with either a chain id or a provider
async
function
_getChainIdAndProvider
(
chainIdOrProvider
:
ChainIdOrProvider
):
Promise
<
_ChainIdAndProvider
>
{
async
function
getChainIdAndProvider
(
chainIdOrProvider
:
ChainIdOrProvider
):
Promise
<
_ChainIdAndProvider
>
{
// if a chainId is provided, get a default provider for it
if
(
isChainId
(
chainIdOrProvider
))
{
return
{
chainId
:
chainIdOrProvider
,
provider
:
ethers
.
getDefaultProvider
(
CHAIN_ID_NAME
[
chainIdOrProvider
])
provider
:
ethers
.
getDefaultProvider
(
_
CHAIN_ID_NAME
[
chainIdOrProvider
])
}
}
// if a provider is provided, fetch the chainId from it
else
{
const
{
chainId
}:
ethers
.
utils
.
Network
=
await
chainIdOrProvider
.
getNetwork
()
if
(
!
(
chainId
in
SUPPORTED_CHAIN_ID
))
{
throw
Error
(
`chainId
${
chainId
}
is not valid.`
)
}
return
{
chainId
,
provider
:
chainIdOrProvider
...
...
@@ -28,13 +31,21 @@ async function _getChainIdAndProvider(chainIdOrProvider: ChainIdOrProvider): Pro
}
}
// get token data from an address and chain id/provider
async
function
_getToken
(
tokenAddress
:
string
,
chainIdAndProvider
:
_ChainIdAndProvider
):
Promise
<
Token
>
{
export
function
getEthToken
(
chainId
?:
number
):
Token
{
return
{
...(
chainId
?
{
chainId
}
:
{}),
address
:
ETH
,
decimals
:
18
}
}
async
function
getToken
(
tokenAddress
:
string
,
chainIdAndProvider
:
_ChainIdAndProvider
):
Promise
<
Token
>
{
if
(
tokenAddress
===
ETH
)
{
return
ETH_TOKEN
(
chainIdAndProvider
.
chainId
)
return
getEthToken
(
chainIdAndProvider
.
chainId
)
}
else
{
const
ERC20Contract
:
ethers
.
Contract
=
_getContract
(
tokenAddress
,
ERC20_ABI
,
chainIdAndProvider
.
provider
)
const
ERC20Contract
:
ethers
.
Contract
=
getContract
(
tokenAddress
,
_
ERC20_ABI
,
chainIdAndProvider
.
provider
)
const
decimals
:
number
=
await
ERC20Contract
.
decimals
()
return
{
chainId
:
chainIdAndProvider
.
chainId
,
address
:
ERC20Contract
.
address
,
...
...
@@ -43,28 +54,31 @@ async function _getToken(tokenAddress: string, chainIdAndProvider: _ChainIdAndPr
}
}
// external function to get token reserves
export
async
function
getTokenReserves
(
tokenAddress
:
string
,
chainIdOrProvider
:
ChainIdOrProvider
=
1
):
Promise
<
TokenReservesNormalized
>
{
const
chainIdAndProvider
:
_ChainIdAndProvider
=
await
_getChainIdAndProvider
(
chainIdOrProvider
)
// validate input arguments
const
normalizedTokenAddress
:
string
=
normalizeAddress
(
tokenAddress
)
const
chainIdAndProvider
:
_ChainIdAndProvider
=
await
getChainIdAndProvider
(
chainIdOrProvider
)
// fetch tokens
const
ethTokenPromise
:
Promise
<
Token
>
=
_
getToken
(
ETH
,
chainIdAndProvider
)
const
tokenPromise
:
Promise
<
Token
>
=
_getToken
(
t
okenAddress
,
chainIdAndProvider
)
// fetch tokens
(async)
const
ethTokenPromise
:
Promise
<
Token
>
=
getToken
(
ETH
,
chainIdAndProvider
)
const
tokenPromise
:
Promise
<
Token
>
=
getToken
(
normalizedT
okenAddress
,
chainIdAndProvider
)
// get contracts
const
factoryContract
:
ethers
.
Contract
=
_
getContract
(
const
factoryContract
:
ethers
.
Contract
=
getContract
(
FACTORY_ADDRESS
[
chainIdAndProvider
.
chainId
],
FACTORY_ABI
,
chainIdAndProvider
.
provider
)
const
tokenContract
:
ethers
.
Contract
=
_getContract
(
tokenAddress
,
ERC20_ABI
,
chainIdAndProvider
.
provider
)
const
tokenContract
:
ethers
.
Contract
=
getContract
(
normalizedTokenAddress
,
_
ERC20_ABI
,
chainIdAndProvider
.
provider
)
const
exchangeAddress
:
string
=
await
factoryContract
.
getExchange
(
tokenContract
.
address
)
// fetch exchange adddress (blocking async)
const
exchangeAddress
:
string
=
await
factoryContract
.
getExchange
(
normalizedTokenAddress
)
const
exchangeTokenPromise
:
Promise
<
Token
>
=
_getToken
(
exchangeAddress
,
chainIdAndProvider
)
// fetch exchange token and eth/token balances (async)
const
exchangeTokenPromise
:
Promise
<
Token
>
=
getToken
(
exchangeAddress
,
chainIdAndProvider
)
const
ethBalancePromise
:
Promise
<
ethers
.
utils
.
BigNumber
>
=
chainIdAndProvider
.
provider
.
getBalance
(
exchangeAddress
)
const
tokenBalancePromise
:
Promise
<
ethers
.
utils
.
BigNumber
>
=
tokenContract
.
balanceOf
(
exchangeAddress
)
...
...
src/format/index.ts
View file @
1fcc0a59
import
BigNumber
from
'
bignumber.js
'
import
{
BigNumberish
,
FlexibleFormat
,
isFormat
,
FormatSignificantOptions
,
FormatFixedOptions
}
from
'
../types
'
import
{
_0
,
_10
,
MAX_DECIMAL_PLACES
,
ROUNDING_MODE
,
FIXED_UNDERFLOW_BEHAVIOR
}
from
'
../constants
'
import
{
_0
,
_10
,
_MAX_DECIMAL_PLACES
,
_
ROUNDING_MODE
,
FIXED_UNDERFLOW_BEHAVIOR
}
from
'
../constants
'
import
{
normalizeBigNumberish
,
ensureBoundedInteger
,
ensureAllUInt256
,
ensureAllUInt8
}
from
'
../_utils
'
function
_format
(
bigNumber
:
BigNumber
,
decimalPlaces
:
number
,
roundingMode
:
BigNumber
.
RoundingMode
=
ROUNDING_MODE
,
roundingMode
:
BigNumber
.
RoundingMode
=
_
ROUNDING_MODE
,
format
:
FlexibleFormat
):
string
{
return
isFormat
(
format
)
||
format
...
...
@@ -17,11 +17,11 @@ function _format(
// bignumberish is converted to significantDigits, then cast back as a bignumber and formatted, dropping trailing 0s
export
function
formatSignificant
(
bigNumberish
:
BigNumberish
,
options
?:
FormatSignificantOptions
):
string
{
const
{
significantDigits
=
6
,
roundingMode
=
ROUNDING_MODE
,
forceIntegerSignificance
=
true
,
format
=
false
}
=
const
{
significantDigits
=
6
,
roundingMode
=
_
ROUNDING_MODE
,
forceIntegerSignificance
=
true
,
format
=
false
}
=
options
||
{}
const
bigNumber
:
BigNumber
=
normalizeBigNumberish
(
bigNumberish
)
ensureBoundedInteger
(
significantDigits
,
[
1
,
MAX_DECIMAL_PLACES
])
ensureBoundedInteger
(
significantDigits
,
[
1
,
_
MAX_DECIMAL_PLACES
])
const
minimumSignificantDigits
:
number
=
forceIntegerSignificance
?
bigNumber
.
integerValue
().
toFixed
().
length
:
0
const
preciseBigNumber
:
BigNumber
=
new
BigNumber
(
...
...
@@ -34,14 +34,14 @@ export function formatSignificant(bigNumberish: BigNumberish, options?: FormatSi
export
function
formatFixed
(
bigNumberish
:
BigNumberish
,
options
?:
FormatFixedOptions
):
string
{
const
{
decimalPlaces
=
4
,
roundingMode
=
ROUNDING_MODE
,
roundingMode
=
_
ROUNDING_MODE
,
dropTrailingZeros
=
true
,
underflowBehavior
=
FIXED_UNDERFLOW_BEHAVIOR
.
ONE_DIGIT
,
format
=
false
}
=
options
||
{}
const
bigNumber
:
BigNumber
=
normalizeBigNumberish
(
bigNumberish
)
ensureBoundedInteger
(
decimalPlaces
,
MAX_DECIMAL_PLACES
)
ensureBoundedInteger
(
decimalPlaces
,
_
MAX_DECIMAL_PLACES
)
const
minimumNonZeroValue
:
BigNumber
=
new
BigNumber
(
decimalPlaces
===
0
?
'
0.5
'
:
`0.
${
'
0
'
.
repeat
(
decimalPlaces
)}
5`
)
if
(
bigNumber
.
isLessThan
(
minimumNonZeroValue
))
{
...
...
@@ -75,8 +75,8 @@ function decimalize(bigNumberish: BigNumberish, decimals: number): BigNumber {
ensureAllUInt8
([
decimals
])
if
(
decimals
>
MAX_DECIMAL_PLACES
)
{
throw
Error
(
`This function does not support decimals greater than
${
MAX_DECIMAL_PLACES
}
.`
)
if
(
decimals
>
_
MAX_DECIMAL_PLACES
)
{
throw
Error
(
`This function does not support decimals greater than
${
_
MAX_DECIMAL_PLACES
}
.`
)
}
return
bigNumber
.
dividedBy
(
_10
.
exponentiatedBy
(
decimals
))
...
...
src/index.ts
View file @
1fcc0a59
...
...
@@ -5,13 +5,17 @@ export {
ETH
,
SUPPORTED_CHAIN_ID
,
FACTORY_ADDRESS
,
FACTORY_ABI
,
EXCHANGE_ABI
,
TRADE_TYPE
,
TRADE_EXACT
,
TRADE_METHODS
,
TRADE_METHOD_IDS
,
FIXED_UNDERFLOW_BEHAVIOR
}
from
'
./constants
'
export
*
from
'
./data
'
export
*
from
'
./computation
'
export
*
from
'
./format
'
export
*
from
'
./orchestration
'
export
*
from
'
./transact
'
src/orchestration/index.ts
View file @
1fcc0a59
import
{
BigNumberish
,
ChainIdOrProvider
,
TokenReservesNormalized
,
MarketDetails
,
TradeDetails
}
from
'
../types
'
import
{
TRADE_TYPE
,
TRADE_EXACT
,
ETH
}
from
'
../constants
'
import
{
BigNumberish
,
ChainIdOrProvider
,
TokenReservesNormalized
,
OptionalReserves
,
MarketDetails
,
TradeDetails
}
from
'
../types
'
import
{
TRADE_EXACT
}
from
'
../constants
'
import
{
getTokenReserves
}
from
'
../data
'
import
{
getMarketDetails
,
getTradeDetails
}
from
'
../computation
'
export
async
function
getTrade
(
inputTokenAddress
:
string
,
outputTokenAddress
:
string
,
tradeType
:
TRADE_TYPE
,
tradeExact
:
TRADE_EXACT
,
tradeAmount
:
BigNumberish
,
//// eth for tokens
export
function
tradeExactEthForTokensWithData
(
reserves
:
OptionalReserves
,
ethAmount
:
BigNumberish
):
TradeDetails
{
const
marketDetails
:
MarketDetails
=
getMarketDetails
(
undefined
,
reserves
)
return
getTradeDetails
(
TRADE_EXACT
.
INPUT
,
ethAmount
,
marketDetails
)
}
export
async
function
tradeExactEthForTokens
(
tokenAddress
:
string
,
ethAmount
:
BigNumberish
,
chainIdOrProvider
?:
ChainIdOrProvider
):
Promise
<
TradeDetails
>
{
const
tokenReserves
:
TokenReservesNormalized
=
await
getTokenReserves
(
tokenAddress
,
chainIdOrProvider
)
return
tradeExactEthForTokensWithData
(
tokenReserves
,
ethAmount
)
}
export
function
tradeEthForExactTokensWithData
(
reserves
:
OptionalReserves
,
tokenAmount
:
BigNumberish
):
TradeDetails
{
const
marketDetails
:
MarketDetails
=
getMarketDetails
(
undefined
,
reserves
)
return
getTradeDetails
(
TRADE_EXACT
.
OUTPUT
,
tokenAmount
,
marketDetails
)
}
export
async
function
tradeEthForExactTokens
(
tokenAddress
:
string
,
tokenAmount
:
BigNumberish
,
chainIdOrProvider
?:
ChainIdOrProvider
):
Promise
<
TradeDetails
>
{
const
tokenReservesInput
:
TokenReservesNormalized
|
null
=
inputTokenAddress
===
ETH
?
null
:
await
getTokenReserves
(
inputTokenAddress
,
chainIdOrProvider
)
const
tokenReservesOutput
:
TokenReservesNormalized
|
null
=
outputTokenAddress
===
ETH
?
null
:
await
getTokenReserves
(
outputTokenAddress
,
chainIdOrProvider
)
const
tokenReserves
:
TokenReservesNormalized
=
await
getTokenReserves
(
tokenAddress
,
chainIdOrProvider
)
return
tradeEthForExactTokensWithData
(
tokenReserves
,
tokenAmount
)
}
//// tokens to eth
export
function
tradeExactTokensForEthWithData
(
reserves
:
OptionalReserves
,
tokenAmount
:
BigNumberish
):
TradeDetails
{
const
marketDetails
:
MarketDetails
=
getMarketDetails
(
reserves
,
undefined
)
return
getTradeDetails
(
TRADE_EXACT
.
INPUT
,
tokenAmount
,
marketDetails
)
}
const
marketDetails
:
MarketDetails
=
getMarketDetails
(
tradeType
,
tokenReservesInput
,
tokenReservesOutput
)
export
async
function
tradeExactTokensForEth
(
tokenAddress
:
string
,
tokenAmount
:
BigNumberish
,
chainIdOrProvider
?:
ChainIdOrProvider
):
Promise
<
TradeDetails
>
{
const
tokenReserves
:
TokenReservesNormalized
=
await
getTokenReserves
(
tokenAddress
,
chainIdOrProvider
)
return
tradeExactTokensForEthWithData
(
tokenReserves
,
tokenAmount
)
}
return
getTradeDetails
(
tradeExact
,
tradeAmount
,
marketDetails
)
export
function
tradeTokensForExactEthWithData
(
reserves
:
OptionalReserves
,
ethAmount
:
BigNumberish
):
TradeDetails
{
const
marketDetails
:
MarketDetails
=
getMarketDetails
(
reserves
,
undefined
)
return
getTradeDetails
(
TRADE_EXACT
.
OUTPUT
,
ethAmount
,
marketDetails
)
}
export
async
function
tradeTokensForExactEth
(
tokenAddress
:
string
,
ethAmount
:
BigNumberish
,
chainIdOrProvider
?:
ChainIdOrProvider
):
Promise
<
TradeDetails
>
{
const
tokenReserves
:
TokenReservesNormalized
=
await
getTokenReserves
(
tokenAddress
,
chainIdOrProvider
)
return
tradeTokensForExactEthWithData
(
tokenReserves
,
ethAmount
)
}
//// tokens for tokens
export
function
tradeExactTokensForTokensWithData
(
reservesInput
:
OptionalReserves
,
reservesOutput
:
OptionalReserves
,
tokenAmount
:
BigNumberish
):
TradeDetails
{
const
marketDetails
:
MarketDetails
=
getMarketDetails
(
reservesInput
,
reservesOutput
)
return
getTradeDetails
(
TRADE_EXACT
.
INPUT
,
tokenAmount
,
marketDetails
)
}
export
async
function
tradeExactTokensForTokens
(
tokenAddressInput
:
string
,
tokenAddressOutput
:
string
,
tokenAmount
:
BigNumberish
,
chainIdOrProvider
?:
ChainIdOrProvider
):
Promise
<
TradeDetails
>
{
const
tokenReservesInput
:
TokenReservesNormalized
=
await
getTokenReserves
(
tokenAddressInput
,
chainIdOrProvider
)
const
tokenReservesOutput
:
TokenReservesNormalized
=
await
getTokenReserves
(
tokenAddressOutput
,
chainIdOrProvider
)
return
tradeExactTokensForTokensWithData
(
tokenReservesInput
,
tokenReservesOutput
,
tokenAmount
)
}
export
function
tradeTokensForExactTokensWithData
(
reservesInput
:
OptionalReserves
,
reservesOutput
:
OptionalReserves
,
tokenAmount
:
BigNumberish
):
TradeDetails
{
const
marketDetails
:
MarketDetails
=
getMarketDetails
(
reservesInput
,
reservesOutput
)
return
getTradeDetails
(
TRADE_EXACT
.
OUTPUT
,
tokenAmount
,
marketDetails
)
}
export
async
function
tradeTokensForExactTokens
(
tokenAddressInput
:
string
,
tokenAddressOutput
:
string
,
tokenAmount
:
BigNumberish
,
chainIdOrProvider
?:
ChainIdOrProvider
):
Promise
<
TradeDetails
>
{
const
tokenReservesInput
:
TokenReservesNormalized
=
await
getTokenReserves
(
tokenAddressInput
,
chainIdOrProvider
)
const
tokenReservesOutput
:
TokenReservesNormalized
=
await
getTokenReserves
(
tokenAddressOutput
,
chainIdOrProvider
)
return
tradeTokensForExactTokensWithData
(
tokenReservesInput
,
tokenReservesOutput
,
tokenAmount
)
}
src/transact/index.ts
0 → 100644
View file @
1fcc0a59
import
BigNumber
from
'
bignumber.js
'
import
{
TokenReservesNormalized
,
TradeDetails
,
MethodArgument
,
ExecutionDetails
,
_SlippageBounds
,
_PartialExecutionDetails
}
from
'
../types
'
import
{
_0
,
_1
,
_10000
,
_MAX_UINT256
,
TRADE_TYPE
,
TRADE_EXACT
,
TRADE_METHODS
,
TRADE_METHOD_IDS
}
from
'
../constants
'
import
{
normalizeAddress
}
from
'
../_utils
'
function
removeUndefined
(
methodArguments
:
(
MethodArgument
|
undefined
)[]):
MethodArgument
[]
{
return
methodArguments
.
filter
((
a
:
MethodArgument
|
undefined
):
boolean
=>
a
!==
undefined
)
as
MethodArgument
[]
}
function
calculateSlippage
(
value
:
BigNumber
,
maxSlippage
:
number
):
_SlippageBounds
{
const
offset
:
BigNumber
=
value
.
multipliedBy
(
maxSlippage
).
dividedBy
(
_10000
)
const
minimum
:
BigNumber
=
value
.
minus
(
offset
).
integerValue
(
BigNumber
.
ROUND_FLOOR
)
const
maximum
:
BigNumber
=
value
.
plus
(
offset
).
integerValue
(
BigNumber
.
ROUND_CEIL
)
return
{
minimum
:
minimum
.
isLessThan
(
_0
)
?
_0
:
minimum
,
maximum
:
maximum
.
isGreaterThan
(
_MAX_UINT256
)
?
_MAX_UINT256
:
maximum
}
}
function
getReserves
(
trade
:
TradeDetails
):
TokenReservesNormalized
{
switch
(
trade
.
tradeType
)
{
case
TRADE_TYPE
.
ETH_TO_TOKEN
:
{
return
trade
.
marketDetailsPre
.
outputReserves
as
TokenReservesNormalized
}
case
TRADE_TYPE
.
TOKEN_TO_ETH
:
{
return
trade
.
marketDetailsPre
.
inputReserves
as
TokenReservesNormalized
}
case
TRADE_TYPE
.
TOKEN_TO_TOKEN
:
{
return
trade
.
marketDetailsPre
.
inputReserves
as
TokenReservesNormalized
}
default
:
{
throw
Error
(
`tradeType
${
trade
.
tradeType
}
is invalid.`
)
}
}
}
function
getMethodName
(
trade
:
TradeDetails
,
transfer
:
boolean
=
false
):
string
{
switch
(
trade
.
tradeType
)
{
case
TRADE_TYPE
.
ETH_TO_TOKEN
:
{
if
(
trade
.
tradeExact
===
TRADE_EXACT
.
INPUT
&&
!
transfer
)
{
return
TRADE_METHODS
.
ethToTokenSwapInput
}
else
if
(
trade
.
tradeExact
===
TRADE_EXACT
.
INPUT
&&
transfer
)
{
return
TRADE_METHODS
.
ethToTokenTransferInput
}
else
if
(
trade
.
tradeExact
===
TRADE_EXACT
.
OUTPUT
&&
!
transfer
)
{
return
TRADE_METHODS
.
ethToTokenSwapOutput
}
else
{
return
TRADE_METHODS
.
ethToTokenTransferOutput
}
}
case
TRADE_TYPE
.
TOKEN_TO_ETH
:
{
if
(
trade
.
tradeExact
===
TRADE_EXACT
.
INPUT
&&
!
transfer
)
{
return
TRADE_METHODS
.
tokenToEthSwapInput
}
else
if
(
trade
.
tradeExact
===
TRADE_EXACT
.
INPUT
&&
transfer
)
{
return
TRADE_METHODS
.
tokenToEthTransferInput
}
else
if
(
trade
.
tradeExact
===
TRADE_EXACT
.
OUTPUT
&&
!
transfer
)
{
return
TRADE_METHODS
.
tokenToEthSwapOutput
}
else
{
return
TRADE_METHODS
.
tokenToEthTransferOutput
}
}
case
TRADE_TYPE
.
TOKEN_TO_TOKEN
:
{
if
(
trade
.
tradeExact
===
TRADE_EXACT
.
INPUT
&&
!
transfer
)
{
return
TRADE_METHODS
.
tokenToTokenSwapInput
}
else
if
(
trade
.
tradeExact
===
TRADE_EXACT
.
INPUT
&&
transfer
)
{
return
TRADE_METHODS
.
tokenToTokenTransferInput
}
else
if
(
trade
.
tradeExact
===
TRADE_EXACT
.
OUTPUT
&&
!
transfer
)
{
return
TRADE_METHODS
.
tokenToTokenSwapOutput
}
else
{
return
TRADE_METHODS
.
tokenToTokenTransferOutput
}
}
default
:
{
throw
Error
(
`tradeType
${
trade
.
tradeType
}
is invalid.`
)
}
}
}
function
getValueAndMethodArguments
(
trade
:
TradeDetails
,
methodName
:
string
,
maxSlippage
:
number
,
deadline
:
number
,
recipient
?:
string
):
_PartialExecutionDetails
{
switch
(
methodName
)
{
case
TRADE_METHODS
.
ethToTokenSwapInput
:
case
TRADE_METHODS
.
ethToTokenTransferInput
:
{
return
{
value
:
trade
.
inputAmount
.
amount
,
methodArguments
:
removeUndefined
([
calculateSlippage
(
trade
.
outputAmount
.
amount
,
maxSlippage
).
minimum
,
deadline
,
recipient
])
}
}
case
TRADE_METHODS
.
ethToTokenSwapOutput
:
case
TRADE_METHODS
.
ethToTokenTransferOutput
:
{
return
{
value
:
calculateSlippage
(
trade
.
inputAmount
.
amount
,
maxSlippage
).
maximum
,
methodArguments
:
removeUndefined
([
trade
.
outputAmount
.
amount
,
deadline
,
recipient
])
}
}
case
TRADE_METHODS
.
tokenToEthSwapInput
:
case
TRADE_METHODS
.
tokenToEthTransferInput
:
{
return
{
value
:
_0
,
methodArguments
:
removeUndefined
([
trade
.
inputAmount
.
amount
,
calculateSlippage
(
trade
.
outputAmount
.
amount
,
maxSlippage
).
minimum
,
deadline
,
recipient
])
}
}
case
TRADE_METHODS
.
tokenToEthSwapOutput
:
case
TRADE_METHODS
.
tokenToEthTransferOutput
:
{
return
{
value
:
_0
,
methodArguments
:
removeUndefined
([
trade
.
outputAmount
.
amount
,
calculateSlippage
(
trade
.
inputAmount
.
amount
,
maxSlippage
).
maximum
,
deadline
,
recipient
])
}
}
case
TRADE_METHODS
.
tokenToTokenSwapInput
:
case
TRADE_METHODS
.
tokenToTokenTransferInput
:
{
if
(
!
trade
.
outputAmount
.
token
.
address
)
{
throw
Error
(
'
trade does not include output token address.
'
)
}
return
{
value
:
_0
,
methodArguments
:
removeUndefined
([
trade
.
inputAmount
.
amount
,
calculateSlippage
(
trade
.
outputAmount
.
amount
,
maxSlippage
).
minimum
,
_1
,
deadline
,
recipient
,
trade
.
outputAmount
.
token
.
address
])
}
}
case
TRADE_METHODS
.
tokenToTokenSwapOutput
:
case
TRADE_METHODS
.
tokenToTokenTransferOutput
:
{
if
(
!
trade
.
outputAmount
.
token
.
address
)
{
throw
Error
(
'
trade does not include output token address.
'
)
}
return
{
value
:
_0
,
methodArguments
:
removeUndefined
([
trade
.
outputAmount
.
amount
,
calculateSlippage
(
trade
.
inputAmount
.
amount
,
maxSlippage
).
maximum
,
_MAX_UINT256
,
deadline
,
recipient
,
trade
.
outputAmount
.
token
.
address
])
}
}
default
:
{
throw
Error
(
`methodName
${
methodName
}
is invalid.`
)
}
}
}
export
function
getExecutionDetails
(
trade
:
TradeDetails
,
maxSlippage
?:
number
,
deadline
?:
number
,
recipient
?:
string
):
ExecutionDetails
{
const
reserves
:
TokenReservesNormalized
=
getReserves
(
trade
)
if
(
!
reserves
.
exchange
||
!
reserves
.
exchange
.
address
)
{
throw
Error
(
'
trade does not include exchange address.
'
)
}
const
methodName
:
string
=
getMethodName
(
trade
,
!!
recipient
)
const
methodId
:
string
=
TRADE_METHOD_IDS
[
methodName
]
const
{
value
,
methodArguments
}:
_PartialExecutionDetails
=
getValueAndMethodArguments
(
trade
,
methodName
,
maxSlippage
||
200
,
deadline
||
Math
.
round
(
Date
.
now
()
/
1000
+
60
*
10
),
recipient
&&
normalizeAddress
(
recipient
)
)
return
{
exchangeAddress
:
reserves
.
exchange
.
address
,
methodName
,
methodId
,
value
,
methodArguments
:
methodArguments
}
}
src/types.ts
View file @
1fcc0a59
...
...
@@ -49,18 +49,22 @@ export interface EthReserves {
}
// type for input data
export
type
OptionalReserves
=
TokenReserves
|
EthReserves
|
undefined
|
null
export
type
OptionalReserves
=
TokenReserves
|
EthReserves
|
undefined
// type guard for OptionalReserves
export
function
areTokenReserves
(
reserves
:
OptionalReserves
):
reserves
is
TokenReserves
{
const
tokenReserves
:
TokenReserves
=
reserves
as
TokenReserves
return
!!
tokenReserves
&&
tokenReserves
.
ethReserve
!==
undefined
&&
tokenReserves
.
tokenReserve
!==
undefined
return
(
tokenReserves
!==
undefined
&&
tokenReserves
.
ethReserve
!==
undefined
&&
tokenReserves
.
tokenReserve
!==
undefined
)
}
// type guard for OptionalReserves
export
function
areETHReserves
(
reserves
:
OptionalReserves
):
reserves
is
Token
Reserves
{
export
function
areETHReserves
(
reserves
:
OptionalReserves
):
reserves
is
Eth
Reserves
{
const
tokenReserves
:
TokenReserves
=
reserves
as
TokenReserves
return
!!
tokenReserves
&&
tokenReserves
.
ethReserve
!==
undefined
&&
tokenReserves
.
tokenReserve
!==
undefined
return
(
tokenReserves
!==
undefined
&&
tokenReserves
.
ethReserve
===
undefined
&&
tokenReserves
.
tokenReserve
===
undefined
)
}
// type for output data
...
...
@@ -97,6 +101,16 @@ export interface TradeDetails {
executionRateSlippage
:
BigNumber
}
export
type
MethodArgument
=
BigNumber
|
number
|
string
export
interface
ExecutionDetails
{
exchangeAddress
:
string
methodName
:
string
methodId
:
string
value
:
BigNumber
methodArguments
:
MethodArgument
[]
}
//// types for formatting data
export
type
FlexibleFormat
=
BigNumber
.
Format
|
boolean
...
...
@@ -147,3 +161,13 @@ export interface _PartialTradeDetails {
inputReservesPost
:
NormalizedReserves
outputReservesPost
:
NormalizedReserves
}
export
interface
_SlippageBounds
{
minimum
:
BigNumber
maximum
:
BigNumber
}
export
interface
_PartialExecutionDetails
{
value
:
BigNumber
methodArguments
:
MethodArgument
[]
}
tsconfig.json
View file @
1fcc0a59
...
...
@@ -12,7 +12,7 @@
"sourceMap"
:
true
/*
Generates
corresponding
'.map'
file.
*/
,
//
"outFile"
:
"./"
,
/*
Concatenate
and
emit
output
to
single
file.
*/
"outDir"
:
"./dist"
/*
Redirect
output
structure
to
the
directory.
*/
,
//
"rootDir"
:
"./src"
/*
Specify
the
root
directory
of
input
files.
Use
to
control
the
output
directory
structure
with
--outDir.
*/
,
"rootDir"
:
"./src"
/*
Specify
the
root
directory
of
input
files.
Use
to
control
the
output
directory
structure
with
--outDir.
*/
,
//
"composite"
:
true
,
/*
Enable
project
compilation
*/
//
"incremental"
:
true
,
/*
Enable
incremental
compilation
*/
//
"tsBuildInfoFile"
:
"./"
,
/*
Specify
file
to
store
incremental
compilation
information
*/
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment