Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
offshiftXFT
offshift-frontend-public
Commits
bde794d5
Commit
bde794d5
authored
2 years ago
by
XFT
Browse files
Options
Download
Email Patches
Plain Diff
.
parent
67aa780a
Pipeline
#28
failed with stages
in 0 seconds
Changes
198
Pipelines
1
Hide whitespace changes
Inline
Side-by-side
Showing
20 changed files
with
1451 additions
and
0 deletions
+1451
-0
src/app/core/interfaces/price-contract.ts
src/app/core/interfaces/price-contract.ts
+10
-0
src/app/core/interfaces/quoterv2-contract.ts
src/app/core/interfaces/quoterv2-contract.ts
+11
-0
src/app/core/interfaces/reward-contract.ts
src/app/core/interfaces/reward-contract.ts
+19
-0
src/app/core/interfaces/reward-unlocked-contract.ts
src/app/core/interfaces/reward-unlocked-contract.ts
+17
-0
src/app/core/interfaces/shifter-contract.ts
src/app/core/interfaces/shifter-contract.ts
+42
-0
src/app/core/interfaces/storage-contract.ts
src/app/core/interfaces/storage-contract.ts
+25
-0
src/app/core/interfaces/swaprouter-contract.ts
src/app/core/interfaces/swaprouter-contract.ts
+11
-0
src/app/core/interfaces/token-contract.ts
src/app/core/interfaces/token-contract.ts
+16
-0
src/app/core/interfaces/tokenswap-contract.ts
src/app/core/interfaces/tokenswap-contract.ts
+10
-0
src/app/core/interfaces/v3staker-contract.ts
src/app/core/interfaces/v3staker-contract.ts
+11
-0
src/app/core/interfaces/weth9-contract.ts
src/app/core/interfaces/weth9-contract.ts
+12
-0
src/app/core/pipes/index.ts
src/app/core/pipes/index.ts
+2
-0
src/app/core/pipes/normalize-bn.pipe.ts
src/app/core/pipes/normalize-bn.pipe.ts
+12
-0
src/app/core/pipes/pipes.module.ts
src/app/core/pipes/pipes.module.ts
+20
-0
src/app/core/pipes/short-address.pipe.ts
src/app/core/pipes/short-address.pipe.ts
+12
-0
src/app/core/reducer.ts
src/app/core/reducer.ts
+81
-0
src/app/core/router-params.serializer.ts
src/app/core/router-params.serializer.ts
+35
-0
src/app/core/selectors.ts
src/app/core/selectors.ts
+127
-0
src/app/core/services/base.service.ts
src/app/core/services/base.service.ts
+35
-0
src/app/core/services/contract.service.ts
src/app/core/services/contract.service.ts
+943
-0
No files found.
src/app/core/interfaces/price-contract.ts
0 → 100644
View file @
bde794d5
import
{
Contract
}
from
'
web3-eth-contract
'
;
import
{
CallReturn
}
from
'
./callback
'
;
export
interface
PriceContractMethods
{
getLatestPrice
(
aggregator
:
number
):
CallReturn
<
any
>
;
}
export
interface
PriceContract
extends
Contract
{
methods
:
PriceContractMethods
;
}
This diff is collapsed.
Click to expand it.
src/app/core/interfaces/quoterv2-contract.ts
0 → 100644
View file @
bde794d5
import
{
Contract
}
from
'
web3-eth-contract
'
;
import
{
CallReturn
,
SendReturn
}
from
'
./callback
'
;
export
interface
QuoterV2ContractMethods
{
quoteExactOutputSingle
(
params
:
string
[]):
CallReturn
<
any
>
quoteExactInputSingle
(
params
:
string
[]):
CallReturn
<
any
>
}
export
interface
QuoterV2Contract
extends
Contract
{
methods
:
QuoterV2ContractMethods
;
}
This diff is collapsed.
Click to expand it.
src/app/core/interfaces/reward-contract.ts
0 → 100644
View file @
bde794d5
import
{
Contract
}
from
'
web3-eth-contract
'
;
import
{
SendReturn
,
CallReturn
}
from
'
./callback
'
;
export
interface
RewardContractMethods
{
shift
(
amount
:
string
):
SendReturn
<
any
>
;
withdraw
(
tokenId
:
string
):
SendReturn
<
any
>
;
harvest
(
tokenId
:
string
):
SendReturn
<
any
>
;
chainlinkPrice
():
CallReturn
<
any
>
;
getETHAmount
(
amount
:
string
):
CallReturn
<
any
>
;
deposits
(
tokenId
:
string
):
CallReturn
<
any
>
;
incentiveKey
():
CallReturn
<
any
>
;
incentiveId
():
CallReturn
<
any
>
;
expiry
():
CallReturn
<
any
>
;
}
export
interface
RewardContract
extends
Contract
{
methods
:
RewardContractMethods
;
}
This diff is collapsed.
Click to expand it.
src/app/core/interfaces/reward-unlocked-contract.ts
0 → 100644
View file @
bde794d5
import
{
Contract
}
from
'
web3-eth-contract
'
;
import
{
SendReturn
,
CallReturn
}
from
'
./callback
'
;
export
interface
RewardUnlockedContractMethods
{
addLiquidity
(
amount
:
string
):
SendReturn
<
any
>
;
withdraw
(
tokenId
:
string
):
SendReturn
<
any
>
;
chainlinkPrice
():
CallReturn
<
any
>
;
getETHAmount
(
amount
:
string
):
CallReturn
<
any
>
;
deposits
(
tokenId
:
string
):
CallReturn
<
any
>
;
incentiveKey
():
CallReturn
<
any
>
;
incentiveId
():
CallReturn
<
any
>
;
}
export
interface
RewardUnlockedContract
extends
Contract
{
methods
:
RewardUnlockedContractMethods
;
}
This diff is collapsed.
Click to expand it.
src/app/core/interfaces/shifter-contract.ts
0 → 100644
View file @
bde794d5
import
{
Contract
}
from
'
web3-eth-contract
'
;
import
{
CallReturn
,
SendReturn
}
from
'
./callback
'
;
export
interface
ShifterContractMethods
{
deposit
(
commitment
:
string
,
encryptedNote
:
string
,
passwordHash
:
string
):
SendReturn
<
any
>
;
withdraw
(
proof
:
string
,
root
:
string
,
nullifierHash
:
string
,
recipient
:
string
,
relayer
:
string
,
fee
:
string
,
refund
:
string
):
SendReturn
<
any
>
;
commitmentList
():
CallReturn
<
any
>
;
commitments
(
commitment
:
string
):
CallReturn
<
any
>
;
simpleShift
(
amount
:
string
,
recipient
:
string
):
SendReturn
<
any
>
getTokensForDenomination
(
denom
:
BigInt
):
CallReturn
<
any
>
getCost
(
denom
:
BigInt
):
CallReturn
<
any
>
isSpent
(
nullifierHash
:
string
):
CallReturn
<
any
>
isSpentArray
(
nullifierHashes
:
string
[]):
CallReturn
<
any
>
denomination
():
CallReturn
<
any
>
chainlinkFeed
():
CallReturn
<
any
>
;
xftPool
():
CallReturn
<
any
>
;
tokenPool
():
CallReturn
<
any
>
;
}
export
interface
ShifterContract
extends
Contract
{
methods
:
ShifterContractMethods
;
}
This diff is collapsed.
Click to expand it.
src/app/core/interfaces/storage-contract.ts
0 → 100644
View file @
bde794d5
import
{
Contract
}
from
'
web3-eth-contract
'
;
import
{
CallReturn
,
SendReturn
}
from
'
./callback
'
;
export
interface
StorageContractMethods
{
store
(
address
:
string
,
_encryptedNote
:
string
):
SendReturn
<
any
>
;
getLatestDeposit
(
mixer
:
string
,
address
:
string
,
passwordHash
:
string
):
CallReturn
<
any
>
;
getDeposits
(
mixer
:
string
,
address
:
string
,
passwordHash
:
string
):
CallReturn
<
any
>
;
getDepositsLength
(
mixer
:
string
,
address
:
string
,
passwordHash
:
string
):
CallReturn
<
any
>
;
getDepositByIndex
(
mixer
:
string
,
address
:
string
,
passwordHash
:
string
,
index
:
string
):
CallReturn
<
any
>
;
xcrypt
(
data
:
string
,
key
:
string
):
CallReturn
<
any
>
;
decrypt
(
address
:
string
,
index
:
string
,
key
:
string
):
CallReturn
<
any
>
;
}
export
interface
StorageContract
extends
Contract
{
methods
:
StorageContractMethods
;
}
This diff is collapsed.
Click to expand it.
src/app/core/interfaces/swaprouter-contract.ts
0 → 100644
View file @
bde794d5
import
{
Contract
}
from
'
web3-eth-contract
'
;
import
{
CallReturn
,
SendReturn
}
from
'
./callback
'
;
export
interface
SwapRouterContractMethods
{
//exactOutputSingle(params: string[]): SendReturn<any>
exactOutputSingle
(
params
:
string
[]):
SendReturn
<
any
>
}
export
interface
SwapRouterContract
extends
Contract
{
methods
:
SwapRouterContractMethods
;
}
This diff is collapsed.
Click to expand it.
src/app/core/interfaces/token-contract.ts
0 → 100644
View file @
bde794d5
import
{
Contract
}
from
'
web3-eth-contract
'
;
import
{
CallReturn
,
SendReturn
}
from
'
./callback
'
;
export
interface
TokenContractMethods
{
allowance
(
owner
:
string
,
spender
:
string
):
CallReturn
<
any
>
;
approve
(
accountAddress
:
string
,
amount
:
string
):
SendReturn
<
any
>
;
balanceOf
(
accountAddress
:
string
):
CallReturn
<
string
>
;
safeApprove
(
accountAddress
:
string
,
amount
:
string
):
SendReturn
<
any
>
}
export
interface
TokenContract
extends
Contract
{
methods
:
TokenContractMethods
;
}
This diff is collapsed.
Click to expand it.
src/app/core/interfaces/tokenswap-contract.ts
0 → 100644
View file @
bde794d5
import
{
Contract
}
from
'
web3-eth-contract
'
;
import
{
SendReturn
}
from
'
./callback
'
;
export
interface
TokenSwapContractMethods
{
upgrade
():
SendReturn
<
any
>
;
}
export
interface
TokenSwapContract
extends
Contract
{
methods
:
TokenSwapContractMethods
;
}
This diff is collapsed.
Click to expand it.
src/app/core/interfaces/v3staker-contract.ts
0 → 100644
View file @
bde794d5
import
{
Contract
}
from
'
web3-eth-contract
'
;
import
{
CallReturn
,
SendReturn
}
from
'
./callback
'
;
export
interface
V3StakerContractMethods
{
getRewardInfo
(
key
:
string
[],
tokenId
:
string
):
CallReturn
<
any
>
;
incentives
(
incentiveId
:
string
):
CallReturn
<
any
>
;
}
export
interface
V3StakerContract
extends
Contract
{
methods
:
V3StakerContractMethods
;
}
This diff is collapsed.
Click to expand it.
src/app/core/interfaces/weth9-contract.ts
0 → 100644
View file @
bde794d5
import
{
Contract
}
from
'
web3-eth-contract
'
;
import
{
SendReturn
}
from
'
./callback
'
;
export
interface
Weth9ContractMethods
{
deposit
():
SendReturn
<
any
>
;
withdraw
(
amount
:
string
):
SendReturn
<
any
>
;
approve
(
spender
:
string
,
amount
:
string
):
SendReturn
<
any
>
;
}
export
interface
Weth9Contract
extends
Contract
{
methods
:
Weth9ContractMethods
;
}
This diff is collapsed.
Click to expand it.
src/app/core/pipes/index.ts
0 → 100644
View file @
bde794d5
export
*
from
'
./pipes.module
'
;
export
*
from
'
./short-address.pipe
'
;
This diff is collapsed.
Click to expand it.
src/app/core/pipes/normalize-bn.pipe.ts
0 → 100644
View file @
bde794d5
import
{
Pipe
,
PipeTransform
}
from
'
@angular/core
'
;
import
{
normalizeBN
,
BigNumberValue
}
from
'
../helpers
'
;
@
Pipe
({
name
:
'
normalizeBN
'
})
export
class
NormalizeBnPipe
implements
PipeTransform
{
public
transform
(
value
:
BigNumberValue
=
'
0
'
,
decimals
:
number
=
18
):
number
{
return
Number
(
normalizeBN
(
value
,
decimals
).
dp
(
5
).
toString
(
10
));
}
}
This diff is collapsed.
Click to expand it.
src/app/core/pipes/pipes.module.ts
0 → 100644
View file @
bde794d5
import
{
NgModule
}
from
'
@angular/core
'
;
import
{
CommonModule
}
from
'
@angular/common
'
;
import
{
NormalizeBnPipe
}
from
'
./normalize-bn.pipe
'
;
import
{
ShortAddressPipe
}
from
'
./short-address.pipe
'
;
@
NgModule
({
declarations
:
[
ShortAddressPipe
,
NormalizeBnPipe
,
],
exports
:
[
ShortAddressPipe
,
NormalizeBnPipe
,
],
imports
:
[
CommonModule
,
]
})
export
class
PipesModule
{
}
This diff is collapsed.
Click to expand it.
src/app/core/pipes/short-address.pipe.ts
0 → 100644
View file @
bde794d5
import
{
Pipe
,
PipeTransform
}
from
'
@angular/core
'
;
import
{
shortAddress
,
isTxHash
,
shortTxHash
}
from
'
../helpers
'
;
@
Pipe
({
name
:
'
shortAddress
'
})
export
class
ShortAddressPipe
implements
PipeTransform
{
public
transform
(
address
:
string
):
string
{
return
isTxHash
(
address
)
?
shortTxHash
(
address
)
:
shortAddress
(
address
);
}
}
This diff is collapsed.
Click to expand it.
src/app/core/reducer.ts
0 → 100644
View file @
bde794d5
import
{
Action
,
createReducer
,
on
}
from
'
@ngrx/store
'
;
import
{
GetAllowanceSuccess
,
GetBalancesSuccess
,
GetLatestPriceSuccess
,
GetXFTBalanceSuccess
,
GetUSDBalanceSuccess
,
SetAccountAddress
,
SetRouterParams
,
}
from
'
./actions
'
;
import
{
RouterState
}
from
'
./index
'
;
import
{
OutputParamsBalance
}
from
'
./interfaces/contract-service-methods
'
;
import
{
TOKENS_MAP
}
from
'
./helpers
'
;
import
{
TokensName
}
from
'
./enums
'
;
import
{
Console
}
from
'
console
'
;
export
const
coreKey
=
'
context
'
;
export
interface
CoreState
extends
RouterState
{
accountAddress
:
string
;
xftBalance
:
string
;
usdBalance
:
string
;
allowance
:
string
;
balances
:
OutputParamsBalance
[];
assetPrice
:
{
price
:
string
;
decimals
:
number
;
};
}
export
const
initialState
:
CoreState
=
{
accountAddress
:
undefined
,
balances
:
undefined
,
xftBalance
:
undefined
,
usdBalance
:
undefined
,
allowance
:
undefined
,
assetPrice
:
undefined
,
params
:
undefined
,
queryParams
:
undefined
,
url
:
undefined
,
};
const
_coreReducer
=
createReducer
(
initialState
,
on
(
SetRouterParams
,
(
state
,
{
url
,
params
,
queryParams
}):
CoreState
=>
{
return
{
...
state
,
url
,
params
,
queryParams
};
}),
on
(
SetAccountAddress
,
(
state
,
{
accountAddress
}):
CoreState
=>
{
return
{
...
state
,
accountAddress
};
}),
// The actual balance state modifications happen here
on
(
GetXFTBalanceSuccess
,
(
state
,
{
xftBalance
}):
CoreState
=>
{
TOKENS_MAP
[
"
XFT
"
][
"
balance
"
]
=
xftBalance
;
return
{
...
state
,
xftBalance
};
}),
on
(
GetUSDBalanceSuccess
,
(
state
,
{
usdBalance
}):
CoreState
=>
{
Object
.
entries
(
TOKENS_MAP
).
forEach
(([
key
,
value
])
=>
value
[
"
zkSymbol
"
]
===
(
"
anonUSD
"
)?
TOKENS_MAP
[
key
][
"
balance
"
]
=
usdBalance
:
TOKENS_MAP
[
key
][
"
balance
"
]
=
"
No USD
"
);
return
{
...
state
,
usdBalance
};
}),
on
(
GetLatestPriceSuccess
,
(
state
,
{
assetPrice
}):
CoreState
=>
{
return
{
...
state
,
assetPrice
};
}),
on
(
GetAllowanceSuccess
,
(
state
,
{
allowance
}):
CoreState
=>
{
return
{
...
state
,
allowance
};
}),
on
(
GetBalancesSuccess
,
(
state
,
{
balances
}):
CoreState
=>
{
balances
?.
forEach
(({
asset
})
=>
{
if
(
asset
.
symbol
&&
TOKENS_MAP
[
asset
.
symbol
])
{
TOKENS_MAP
[
asset
.
symbol
].
balance
=
asset
.
amount
;
}
});
return
{
...
state
,
balances
};
}),
);
export
function
reducer
(
state
:
CoreState
,
action
:
Action
):
CoreState
{
return
_coreReducer
(
state
,
action
);
}
This diff is collapsed.
Click to expand it.
src/app/core/router-params.serializer.ts
0 → 100644
View file @
bde794d5
import
{
Params
,
RouterStateSnapshot
}
from
'
@angular/router
'
;
import
{
RouterStateSerializer
}
from
'
@ngrx/router-store
'
;
import
{
RouterParams
,
RouterState
,
initialRouterParamsState
}
from
'
./index
'
;
export
class
RouterParamsSerializer
implements
RouterStateSerializer
<
RouterState
>
{
public
serialize
({
url
,
root
}:
RouterStateSnapshot
):
RouterState
{
let
route
=
root
;
let
queryParams
:
Params
=
{};
let
params
:
RouterParams
=
initialRouterParamsState
;
while
(
route
.
firstChild
)
{
route
=
route
.
firstChild
;
params
=
{
...
params
,
...
parseParams
(
route
.
params
)
};
queryParams
=
{
...
queryParams
,
...
parseParams
(
route
.
queryParams
)
};
}
return
{
url
,
params
,
queryParams
};
}
}
function
parseParams
(
params
:
Params
):
Params
{
const
obj
:
Params
=
{};
for
(
const
param
in
params
)
{
if
(
params
.
hasOwnProperty
(
param
))
{
obj
[
param
]
=
!
params
[
param
].
startsWith
(
'
0x
'
)
&&
!
isNaN
(
+
params
[
param
])
?
+
params
[
param
]
:
params
[
param
];
}
}
return
obj
;
}
This diff is collapsed.
Click to expand it.
src/app/core/selectors.ts
0 → 100644
View file @
bde794d5
import
{
createFeatureSelector
,
createSelector
}
from
'
@ngrx/store
'
;
import
{
coreKey
,
CoreState
}
from
'
./reducer
'
;
import
{
normalizeBN
,
TOKENS_MAP
,
valueToBigNumber
}
from
'
./helpers
'
;
import
{
Tokens
,
TokensName
}
from
'
./enums
'
;
export
const
selectContextState
=
createFeatureSelector
<
CoreState
>
(
coreKey
);
export
const
selectContext
=
createSelector
(
selectContextState
,
(
context
)
=>
context
,
);
export
const
selectAccountAddress
=
createSelector
(
selectContext
,
(
state
)
=>
state
.
accountAddress
,
);
export
const
selectXFTBalance
=
createSelector
(
selectContext
,
(
state
)
=>
state
.
xftBalance
,
);
export
const
selectUSDBalance
=
createSelector
(
selectContext
,
(
state
)
=>
state
.
usdBalance
,
);
export
const
selectAssetPrice
=
createSelector
(
selectContext
,
(
state
)
=>
state
.
assetPrice
,
);
export
const
selectAllowance
=
createSelector
(
selectContext
,
(
state
)
=>
state
.
allowance
,
);
export
const
selectBalances
=
createSelector
(
selectContext
,
(
state
)
=>
{
return
state
?.
balances
?.
map
((
balance
)
=>
{
return
{
...
TOKENS_MAP
[
balance
.
asset
.
symbol
],
...
balance
,
};
});
},
);
export
const
selectAssets
=
createSelector
(
selectBalances
,
(
balances
)
=>
{
return
Object
.
values
(
TOKENS_MAP
)
.
filter
(({
zkSymbol
})
=>
zkSymbol
!==
"
XFT
"
)
//TokensName.XFT)
.
map
((
token
)
=>
{
const
balance
=
balances
?.
find
((
b
)
=>
b
.
asset
.
symbol
===
token
.
zkSymbol
);
return
{
...
token
,
asset
:
{
symbol
:
token
.
zkSymbol
,
amount
:
balance
?
balance
.
asset
.
amount
:
'
0
'
,
USD
:
balance
?
balance
.
asset
.
USD
:
'
0
'
,
XFT
:
balance
?
balance
.
asset
.
XFT
:
'
0
'
,
},
commitments
:
balance
?
balance
.
commitments
:
[],
};
});
},
);
// Used in wallet component
export
const
selectXFTBalancesAmount
=
createSelector
(
selectBalances
,
(
balances
)
=>
{
const
amount
=
balances
?.
map
((
balance
)
=>
balance
.
asset
.
XFT
)
.
reduce
((
prev
,
cur
)
=>
{
prev
=
prev
.
plus
(
cur
);
return
prev
;
},
valueToBigNumber
(
0
));
return
normalizeBN
(
amount
,
18
).
dp
(
2
).
toString
(
10
);
},
);
export
const
selectTokenBySymbol
=
(
symbol
:
string
)
=>
{
return
createSelector
(
selectBalances
,
(
balances
)
=>
balances
?.
find
(({
asset
})
=>
symbol
===
asset
.
symbol
),
);
};
export
const
selectChartData
=
createSelector
(
selectBalances
,
(
balances
)
=>
{
const
data
=
balances
?.
map
((
b
)
=>
{
return
normalizeBN
(
b
.
asset
.
amount
,
18
)
.
dp
(
5
)
.
toNumber
();
});
return
{
labels
:
Object
.
values
(
Tokens
).
map
((
symbol
)
=>
`
${
symbol
}
`
),
datasets
:
[
{
data
,
label
:
''
,
borderWidth
:
0
,
backgroundColor
:
[
'
#5800B0
'
,
'
#6B39FA
'
,
'
#A98CFF
'
,
'
#D1C1FE
'
,
],
hoverBackgroundColor
:
[
'
#5800B0
'
,
'
#6B39FA
'
,
'
#A98CFF
'
,
'
#D1C1FE
'
,
],
},
],
};
},
);
This diff is collapsed.
Click to expand it.
src/app/core/services/base.service.ts
0 → 100644
View file @
bde794d5
import
{
Store
}
from
'
@ngrx/store
'
;
import
{
firstValueFrom
}
from
'
rxjs
'
;
import
{
environment
}
from
'
../../../environments/environment
'
;
import
{
State
}
from
'
../index
'
;
import
{
CallReturn
,
MethodCallback
,
SendReturn
}
from
'
../interfaces/callback
'
;
import
{
selectAccountAddress
}
from
'
../selectors
'
;
export
abstract
class
BaseService
{
protected
accountAddress
!
:
string
;
protected
constructor
(
protected
readonly
store
:
Store
,
)
{
}
protected
apiUrl
():
string
{
return
environment
.
apiUrl
;
}
protected
async
call
<
T
=
any
>
(
method
:
CallReturn
<
T
>
,
cb
:
MethodCallback
=
null
):
Promise
<
T
>
{
const
from
=
await
firstValueFrom
(
this
.
store
.
select
(
selectAccountAddress
));
return
await
method
.
call
({
from
},
cb
);
}
protected
async
send
<
T
=
any
>
(
method
:
SendReturn
<
T
>
,
cb
:
MethodCallback
=
null
):
Promise
<
T
>
{
const
from
=
await
firstValueFrom
(
this
.
store
.
select
(
selectAccountAddress
));
const
gas
=
await
method
.
estimateGas
({
from
});
return
await
method
.
send
({
from
,
gas
},
cb
);
}
}
This diff is collapsed.
Click to expand it.
src/app/core/services/contract.service.ts
0 → 100644
View file @
bde794d5
import
{
HttpClient
}
from
'
@angular/common/http
'
;
import
{
Injectable
}
from
'
@angular/core
'
;
import
{
isAddress
}
from
'
@ethersproject/address
'
;
import
{
Store
}
from
'
@ngrx/store
'
;
import
{
Observable
}
from
'
rxjs
'
;
import
{
AbiItem
}
from
'
web3-utils
'
;
import
{
environment
}
from
'
../../../environments/environment
'
;
import
{
BalanceContract
,
RecipientCommitment
,
SchnorrSignatureSet
}
from
'
../interfaces/balance-contract
'
;
import
{
MethodCallback
}
from
'
../interfaces/callback
'
;
import
{
InitData
,
InputParamsBalance
,
InputParamsBurnCost
,
InputParamsExchange
,
InputParamsPrice
,
OutputParamsBalance
,
}
from
'
../interfaces/contract-service-methods
'
;
import
{
PriceContract
}
from
'
../interfaces/price-contract
'
;
import
{
TokenContract
}
from
'
../interfaces/token-contract
'
;
import
{
ShifterContract
}
from
'
../interfaces/shifter-contract
'
;
import
{
StorageContract
}
from
'
../interfaces/storage-contract
'
import
{
SwapRouterContract
}
from
'
../interfaces/swaprouter-contract
'
import
{
Weth9Contract
}
from
'
../interfaces/weth9-contract
'
import
{
ChainlinkContract
}
from
'
../interfaces/chainlink-contract
'
import
{
TokenSwapContract
}
from
'
../interfaces/tokenswap-contract
'
import
{
RewardContract
}
from
'
../interfaces/reward-contract
'
;
import
{
QuoterV2Contract
}
from
'
../interfaces/quoterv2-contract
'
import
{
OracleContract
}
from
'
../interfaces/oracle-contract
'
;
import
{
RewardUnlockedContract
}
from
'
../interfaces/reward-unlocked-contract
'
import
{
BaseService
}
from
'
./base.service
'
;
import
{
BALANCE_CONTRACT_ABI
,
PRICE_CONTRACT_ABI
,
TOKEN_CONTRACT_ABI
,
SHIFTER_CONTRACT_ABI
,
STORAGE_CONTRACT_ABI
,
AUSD_CONTRACT_ABI
,
SWAPROUTER_CONTRACT_ABI
,
WETH9_CONTRACT_ABI
,
CHAINLINK_CONTRACT_ABI
,
TOKENSWAP_CONTRACT_ABI
,
REWARDER_contract_abi
,
REWARDERUNLOCKED_CONTRACT_ABI
,
QUOTERV2_CONTRACT_ABI
,
V3STAKER_CONTRACT_ABI
,
ORACLE_CONTRACT_ABI
}
from
'
./contracts-abi
'
;
import
{
WalletService
}
from
'
./wallet.service
'
;
import
{
Contract
,
EventData
}
from
'
web3-eth-contract
'
;
import
{
BigNumberValue
,
valueToBigNumber
}
from
'
../helpers
'
;
import
{
TokensName
}
from
'
../enums
'
;
import
{
buffPedersenHash
,
randomBN
,
toFixedHex
,
parseNote
,
parseSaveNote
}
from
'
./crypto
'
;
import
{
Dictionary
}
from
'
@ngrx/entity
'
;
import
{
Buffer
}
from
'
buffer
'
;
import
{
TOKENS_MAP
}
from
'
../helpers/index
'
import
{
local
}
from
'
web3modal
'
;
import
{
V3StakerContract
}
from
'
../interfaces/v3staker-contract
'
;
const
websnarkUtils
=
require
(
'
websnark-backup/src/utils
'
)
const
buildGroth16
=
require
(
'
websnark-backup/src/groth16
'
)
const
stringifyBigInts
=
require
(
'
websnark-backup/tools/stringifybigint
'
).
stringifyBigInts
const
snarkjs
=
require
(
'
snarkjs-backup
'
)
const
bigInt
=
snarkjs
.
bigInt
const
MerkleTree
=
require
(
'
fixed-merkle-tree-backup
'
)
const
crypto
=
require
(
'
crypto
'
)
const
subtle
=
globalThis
.
crypto
.
subtle
const
circomlib
=
require
(
'
circomlib-backup
'
)
const
{
toBN
,
keccak256
,
fromWei
,
randomHex
,
randomBytes
}
=
require
(
'
web3-utils
'
)
const
Web3
=
require
(
'
web3
'
)
const
CUT_LENGTH
=
31
const
CONTRACT_MAP
:
Map
<
string
,
Contract
>
=
new
Map
<
string
,
Contract
>
([]);
const
circuit
=
require
(
"
./withdraw.json
"
)
const
req
=
new
XMLHttpRequest
();
const
rbigint
=
(
nbytes
:
number
)
=>
snarkjs
.
bigInt
.
leBuff2int
(
crypto
.
randomBytes
(
nbytes
));
let
provingKey
:
any
let
groth16
:
any
const
loadKey
=
()
=>
{
return
new
Promise
((
resolve
,
reject
)
=>
{
req
.
open
(
"
GET
"
,
"
./assets/withdraw_proving_key.bin
"
,
true
);
req
.
responseType
=
"
arraybuffer
"
;
req
.
onload
=
(
event
)
=>
{
resolve
(
req
.
response
);
};
req
.
send
(
null
);
})
}
@
Injectable
({
providedIn
:
'
root
'
})
export
class
ContractService
extends
BaseService
{
relayerConfig
:
any
;
constructor
(
store
:
Store
,
private
readonly
_http
:
HttpClient
,
private
readonly
_walletService
:
WalletService
)
{
super
(
store
);
}
public
isAddress
=
(
address
:
string
)
=>
{
return
Web3
.
utils
.
isAddress
(
address
);
}
public
async
relayWithdrawTransaction
(
saveNote
:
string
,
_recipient
:
string
,
shifterAddress
:
string
,
cb
:
MethodCallback
=
null
):
Promise
<
any
>
{
const
{
args
,
proof
}
=
await
this
.
prepareWithdraw
(
saveNote
,
_recipient
,
shifterAddress
)
// Post to the relay server
const
receipt
=
await
this
.
_http
.
post
<
any
>
(
`
${
environment
.
relayerEndpoint
}
/relay`
,
{
proof
:
proof
,
args
:
args
,
shifter
:
shifterAddress
,
callback
:
cb
}).
toPromise
();
return
receipt
;
}
// Populates relayerConfig with data from config file
public
async
getRelayerConfig
()
{
return
this
.
_http
.
get
(
environment
.
relayerEndpoint
+
"
/config
"
)
.
toPromise
()
.
then
(
data
=>
this
.
relayerConfig
=
data
);
}
public
getPrice
(
payload
:
InputParamsPrice
):
Observable
<
any
>
{
return
this
.
_http
.
post
<
any
>
(
this
.
apiUrl
(
'
getPrice
'
),
payload
);
}
public
async
getETHBalance
(
address
:
string
):
Promise
<
any
>
{
return
this
.
_walletService
.
web3
.
eth
.
getBalance
(
address
)
}
public
async
getDenomination
(
shifter
:
string
):
Promise
<
string
>
{
const
{
methods
}
=
this
.
_getShifterContract
(
shifter
);
return
await
this
.
call
(
methods
.
denomination
())
}
public
async
getBurnCost
(
shifter
:
string
,
amount
:
BigInt
,
cb
:
MethodCallback
=
null
):
Promise
<
any
>
{
const
{
methods
}
=
this
.
_getShifterContract
(
shifter
);
return
await
this
.
call
(
methods
.
getCost
(
amount
),
cb
);
}
public
async
getCost
(
shifter
:
string
,
amount
:
BigInt
,
user
:
string
,
cb
:
MethodCallback
=
null
):
Promise
<
any
>
{
const
shifterMethods
=
this
.
_getShifterContract
(
shifter
).
methods
const
chainlinkFeed
=
await
shifterMethods
.
chainlinkFeed
().
call
({
from
:
user
})
const
xftPool
=
await
shifterMethods
.
xftPool
().
call
({
from
:
user
})
const
{
methods
}
=
this
.
_getOracleContract
();
return
methods
.
getCost
(
amount
,
chainlinkFeed
,
xftPool
).
call
({
from
:
user
},
cb
);
}
public
async
getCostSimpleShift
(
shifter
:
string
,
amount
:
BigInt
,
user
:
string
,
cb
:
MethodCallback
=
null
):
Promise
<
any
>
{
const
shifterMethods
=
this
.
_getShifterContract
(
shifter
).
methods
const
chainlinkFeed
=
await
shifterMethods
.
chainlinkFeed
().
call
({
from
:
user
})
const
xftPool
=
await
shifterMethods
.
xftPool
().
call
({
from
:
user
})
const
tokenPool
=
await
shifterMethods
.
tokenPool
().
call
({
from
:
user
})
const
{
methods
}
=
this
.
_getOracleContract
();
return
methods
.
getCostSimpleShift
(
amount
,
chainlinkFeed
,
xftPool
,
tokenPool
).
call
({
from
:
user
},
cb
);
}
public
async
getBurnCostOracle
(
amount
:
BigInt
,
chainlinkFeed
:
string
,
xftPool
:
string
,
cb
:
MethodCallback
=
null
):
Promise
<
any
>
{
const
{
methods
}
=
this
.
_getOracleContract
();
return
await
this
.
call
(
methods
.
getCost
(
amount
,
chainlinkFeed
,
xftPool
),
cb
);
}
public
exchange
(
payload
:
InputParamsExchange
):
Observable
<
any
>
{
return
this
.
_http
.
post
<
any
>
(
this
.
apiUrl
(
'
exchange
'
),
payload
);
}
public
balances
(
payload
:
InputParamsBalance
):
Observable
<
OutputParamsBalance
[]
>
{
return
new
Observable
();
// stub the call
return
this
.
_http
.
post
<
OutputParamsBalance
[]
>
(
this
.
apiUrl
(
'
balances
'
),
payload
);
}
public
init
(
payload
:
InitData
):
Observable
<
any
>
{
return
new
Observable
();
// stub the call
return
this
.
_http
.
post
<
any
>
(
this
.
apiUrl
(
'
init
'
),
payload
);
}
public
async
approve
(
amount
:
string
,
address
:
string
,
user
:
string
,
cb
:
MethodCallback
=
null
):
Promise
<
any
>
{
const
{
methods
}
=
this
.
_getWETH9Contract
()
return
methods
.
approve
(
address
,
amount
).
send
({
from
:
user
},
cb
)
}
public
async
approveXFT
(
amount
:
string
,
address
:
string
,
tokenAddress
:
string
,
user
:
string
,
cb
:
MethodCallback
=
null
):
Promise
<
any
>
{
const
{
methods
}
=
this
.
_getTokenContract
(
tokenAddress
)
return
methods
.
approve
(
address
,
amount
).
send
({
from
:
user
},
cb
)
}
public
async
allowance
(
token
:
string
,
owner
:
string
,
spender
:
string
,
cb
:
MethodCallback
=
null
,
):
Promise
<
any
>
{
const
{
methods
}
=
this
.
_getTokenContract
(
token
);
return
this
.
call
(
methods
.
allowance
(
owner
,
spender
),
cb
);
}
public
async
safeApprove
(
amount
:
string
,
token
:
string
,
address
:
string
,
user
:
string
,
cb
:
MethodCallback
=
null
):
Promise
<
any
>
{
const
{
methods
}
=
this
.
_getTokenContract
(
token
)
return
methods
.
safeApprove
(
address
,
amount
).
send
({
from
:
user
},
cb
)
}
public
xcrypt
=
async
(
data
:
string
,
password
:
string
,
shifter
:
string
,
address
:
string
,
nonce
:
number
=
null
)
=>
{
const
{
methods
}
=
this
.
_getStorageContract
();
if
(
!
nonce
&&
nonce
!==
0
)
nonce
=
(
await
methods
.
getDepositsLength
(
shifter
,
address
,
keccak256
(
password
)).
call
());
const
iv
=
(
await
subtle
.
digest
(
'
SHA-256
'
,
new
Uint8Array
(
Buffer
.
from
((
password
+
nonce
))))).
slice
(
0
,
16
);
const
dataBuffer
=
new
Uint8Array
(
Buffer
.
from
(
data
.
slice
(
2
),
'
hex
'
));
const
keyBuffer
=
new
Uint8Array
(
Buffer
.
from
(
password
.
slice
(
2
),
'
hex
'
));
const
key
=
await
subtle
.
importKey
(
'
raw
'
,
keyBuffer
,
{
name
:
'
AES-GCM
'
},
false
,
[
'
encrypt
'
]);
try
{
let
encrypted
=
await
subtle
.
encrypt
({
name
:
'
AES-GCM
'
,
iv
},
key
,
dataBuffer
);
return
"
0x
"
+
Buffer
.
from
(
encrypted
).
toString
(
'
hex
'
).
slice
(
0
,
124
);
}
catch
(
err
)
{
throw
new
Error
(
"
The data provided couldn't be encrypted or decrypted, please check the inputs
"
);
}
}
public
async
deposit
(
address
:
string
,
amount
:
BigNumberValue
,
currency
:
TokensName
,
cb
:
MethodCallback
=
null
,
):
Promise
<
any
>
{
const
{
methods
}
=
this
.
_getBalanceContract
();
const
{
amountIn
,
assetEnum
:
asset
,
commitment
,
message
,
aggregatePubKey
:
publicKey
,
aggregaterR
:
ecR
,
aggregateS
:
s
,
}
=
await
this
.
_http
.
post
<
any
>
(
this
.
apiUrl
(
'
deposit
'
),
{
address
,
amount
:
valueToBigNumber
(
amount
).
toNumber
(),
currency
}).
toPromise
();
const
recipientCommitment
:
RecipientCommitment
=
{
commitment
,
asset
};
const
schnorrSignatureSet
:
SchnorrSignatureSet
=
{
message
,
publicKey
,
ecR
,
s
};
return
this
.
send
(
methods
.
deposit
(
amountIn
,
amount
,
recipientCommitment
,
schnorrSignatureSet
),
cb
);
}
public
async
withdraw
(
address
:
string
,
amount
:
BigNumberValue
,
commitmentId
:
BigNumberValue
,
cb
:
MethodCallback
=
null
,
):
Promise
<
any
>
{
const
{
message
,
aggregatePubKey
:
publicKey
,
aggregaterR
:
ecR
,
aggregateS
:
s
,
}
=
await
this
.
_http
.
post
<
any
>
(
this
.
apiUrl
(
'
withdraw
'
),
{
address
,
amount
:
valueToBigNumber
(
amount
).
toNumber
(),
commitmentId
:
Number
(
commitmentId
),
}).
toPromise
();
const
schnorrSignatureSet
:
SchnorrSignatureSet
=
{
message
,
publicKey
,
ecR
,
s
};
const
{
methods
}
=
this
.
_getBalanceContract
();
return
this
.
send
(
methods
.
withdraw
(
amount
,
Number
(
commitmentId
),
schnorrSignatureSet
),
cb
);
}
// Get all notes for a given address
public
async
getAggregateDeposits
(
shifters
:
string
[],
address
:
string
,
decrypted
:
boolean
):
Promise
<
any
>
{
const
{
methods
}
=
this
.
_getStorageContract
();
const
password
=
this
.
getOrSetPasswordLocally
();
// Should never be null
let
encryptedNotes
:
any
[]
=
[];
let
decryptedNotes
:
any
[]
=
[];
let
spentNotes
:
any
[]
=
[];
for
(
let
shifter
in
shifters
)
{
shifter
=
shifters
[
shifter
];
if
(
password
)
{
// There should always be a password set by the time we reach this
let
passwordHash
=
keccak256
(
password
);
let
shifterNotes
=
await
this
.
call
(
methods
.
getDeposits
(
shifter
,
address
,
passwordHash
));
shifterNotes
=
shifterNotes
.
map
((
note
:
string
,
index
:
number
)
=>
{
return
{
"
note
"
:
note
,
"
shifter
"
:
shifter
,
"
index
"
:
index
}
});
try
{
encryptedNotes
=
encryptedNotes
.
concat
(
shifterNotes
);
}
catch
(
e
)
{
console
.
log
(
e
)
};
}
else
{
throw
(
"
No password set
"
);
}
}
let
nullHashArray
;
let
boolSpentArray
:
string
[];
let
decryptedUnspentNotes
;
if
(
decrypted
)
{
for
(
let
index
in
encryptedNotes
)
{
let
thisNote
=
encryptedNotes
[
index
];
let
thisDecryptedNote
=
(
await
this
.
xcrypt
(
thisNote
.
note
,
password
,
thisNote
.
shifter
,
address
,
parseInt
(
thisNote
.
index
)));
let
deposited
=
await
this
.
_getShifterContract
(
thisNote
.
shifter
).
methods
.
commitments
(
parseSaveNote
(
thisDecryptedNote
).
commitmentHex
).
call
()
let
spent
=
await
this
.
_getShifterContract
(
thisNote
.
shifter
).
methods
.
isSpent
(
parseSaveNote
(
thisDecryptedNote
).
nullifierHex
).
call
();
// Make sure the note is unspent
if
(
!
spent
&&
deposited
)
decryptedNotes
.
push
({
"
note
"
:
thisDecryptedNote
,
"
shifter
"
:
thisNote
.
shifter
})
// Aggregates spent notes
else
if
(
spent
&&
deposited
)
spentNotes
.
push
({
"
note
"
:
thisDecryptedNote
,
"
shifter
"
:
thisNote
.
shifter
})
}
decryptedNotes
=
decryptedNotes
.
map
((
note
,
idx
:
number
)
=>
{
return
{
"
note
"
:
note
.
note
,
"
shifter
"
:
note
.
shifter
,
"
commitment
"
:
parseSaveNote
(
note
.
note
).
commitmentHex
}
});
spentNotes
=
spentNotes
.
map
((
note
,
idx
:
number
)
=>
{
return
{
"
note
"
:
note
.
note
,
"
shifter
"
:
note
.
shifter
,
"
commitment
"
:
parseSaveNote
(
note
.
note
).
commitmentHex
}
});
}
return
(
decrypted
?
{
decryptedNotes
,
spentNotes
}
:
encryptedNotes
);
}
public
async
getLatestDeposit
(
shifter
:
string
,
address
:
string
):
Promise
<
any
>
{
const
{
methods
}
=
this
.
_getStorageContract
();
const
password
=
this
.
getOrSetPasswordLocally
()
let
encryptedNote
;
if
(
password
)
{
try
{
let
passwordHash
=
keccak256
(
password
)
encryptedNote
=
await
this
.
call
(
methods
.
getLatestDeposit
(
shifter
,
address
,
passwordHash
))
}
catch
(
e
)
{
console
.
log
(
e
)
};
}
if
(
!
encryptedNote
)
{
console
.
log
(
"
No note found
"
)
return
Promise
.
resolve
(
null
);
// No note found
}
console
.
log
(
`Found note:
${
encryptedNote
}
`
)
console
.
log
(
`Decrypted note:
${
await
this
.
xcrypt
(
encryptedNote
,
password
,
shifter
,
address
)}
`
)
return
this
.
xcrypt
(
encryptedNote
,
password
,
shifter
,
address
)
}
public
async
depositAnon
(
/*amount: BigNumberValue,
currency: TokensName,*/
address
:
string
,
shifterAddress
:
string
,
cb
:
MethodCallback
=
null
,
):
Promise
<
any
>
{
let
config
=
JSON
.
parse
(
localStorage
.
getItem
(
'
config
'
))
let
noStorage
=
config
[
localStorage
.
getItem
(
'
account
'
)].
noStorage
const
{
methods
}
=
this
.
_getShifterContract
(
shifterAddress
);
const
{
saveNote
,
hexNote
,
commitmentHex
,
password
}
=
this
.
prepareDeposit
();
let
passwordHash
=
keccak256
(
noStorage
?
crypto
.
randomBytes
(
32
)
:
password
);
const
encryptedNote
=
await
this
.
xcrypt
(
noStorage
?
crypto
.
randomBytes
(
62
)
:
saveNote
,
password
,
shifterAddress
,
address
);
let
tx
=
await
methods
.
deposit
(
commitmentHex
,
encryptedNote
,
passwordHash
).
send
({
from
:
address
,
gas
:
1300000
,
value
:
"
50000000000000000
"
},
cb
)
// Download saveNote
if
(
noStorage
)
this
.
download
(
saveNote
,
commitmentHex
,
shifterAddress
);
return
tx
;
}
public
async
withdrawAnon
(
saveNote
:
string
,
_recipient
:
string
,
shifterAddress
:
string
,
cb
:
MethodCallback
=
null
):
Promise
<
any
>
{
console
.
log
(
"
Save note:
"
+
saveNote
)
const
{
methods
}
=
this
.
_getShifterContract
(
shifterAddress
)
const
{
args
,
proof
}
=
await
this
.
prepareWithdraw
(
saveNote
,
_recipient
,
shifterAddress
)
const
{
root
,
nullifierHash
,
recipient
,
relayer
,
fee
,
refund
}
=
args
return
this
.
send
(
methods
.
withdraw
(
proof
,
root
,
nullifierHash
,
recipient
,
relayer
,
fee
,
refund
),
cb
)
}
public
generatePassword
=
()
=>
randomHex
(
32
);
public
getOrSetPasswordLocally
=
()
=>
{
// add account object
let
config
=
JSON
.
parse
(
localStorage
.
getItem
(
'
config
'
))
let
acc
=
config
[
localStorage
.
getItem
(
'
account
'
)]
if
(
!
acc
.
password
)
{
acc
.
password
=
this
.
generatePassword
();
}
config
[
localStorage
.
getItem
(
'
account
'
)]
=
acc
;
localStorage
.
setItem
(
'
config
'
,
JSON
.
stringify
(
config
))
return
acc
.
password
}
public
prepareDeposit
()
{
const
secret
=
rbigint
(
31
)
const
nullifier
=
rbigint
(
31
)
const
preimage
=
Buffer
.
concat
([
nullifier
.
leInt2Buff
(
31
),
secret
.
leInt2Buff
(
31
)])
const
commitment
=
buffPedersenHash
(
preimage
)
const
commitmentHex
=
toFixedHex
(
commitment
)
const
saveNote
=
`0x
${
nullifier
.
toString
(
16
,
'
hex
'
).
padEnd
(
62
,
'
0
'
)}${
secret
.
toString
(
16
,
'
hex
'
).
padEnd
(
62
,
'
0
'
)}
`
;
const
hexNote
=
`0x
${
preimage
.
toString
(
'
hex
'
)}
`
const
password
=
this
.
getOrSetPasswordLocally
();
return
{
saveNote
,
hexNote
,
commitmentHex
,
password
}
}
async
prepareWithdraw
(
saveNote
:
string
,
recipient
:
string
,
shifterAddress
:
string
,
):
Promise
<
any
>
{
const
{
note
,
tree
,
root
}
=
await
this
.
buildTree
(
saveNote
,
20
,
shifterAddress
)
const
{
args
,
proof
}
=
await
this
.
createSnarkProof
(
root
,
note
,
tree
,
recipient
,
tree
.
indexOf
(
note
.
commitmentHex
)
)
return
{
args
,
proof
}
}
async
buildTree
(
saveNote
:
string
,
levels
:
number
,
shifterAddress
:
string
,
cb
:
MethodCallback
=
null
):
Promise
<
any
>
{
const
note
=
parseSaveNote
(
saveNote
)
const
{
methods
}
=
this
.
_getShifterContract
(
shifterAddress
);
let
leaves
=
await
this
.
call
(
methods
.
commitmentList
(),
cb
)
const
tree
=
new
MerkleTree
(
levels
,
leaves
)
return
{
note
,
tree
,
root
:
tree
.
root
()
}
}
async
createSnarkProof
(
root
:
string
,
note
:
any
,
tree
:
any
,
recipient
:
string
,
leafIndex
:
number
,
):
Promise
<
any
>
{
const
{
pathElements
,
pathIndices
}
=
tree
.
path
(
leafIndex
)
let
relayer
,
fee
,
refund
,
chainId
if
(
environment
.
useRelayer
)
{
await
this
.
getRelayerConfig
();
relayer
=
this
.
relayerConfig
.
address
fee
=
this
.
relayerConfig
.
fee
refund
=
this
.
relayerConfig
.
refund
chainId
=
this
.
relayerConfig
.
chainId
// Not used yet
}
else
{
relayer
=
recipient
fee
=
0
refund
=
0
chainId
=
1
}
const
input
=
stringifyBigInts
({
// public
root
:
tree
.
root
(),
nullifierHash
:
note
.
nullifierHash
,
relayer
,
recipient
:
BigInt
(
recipient
),
fee
,
refund
,
// private
nullifier
:
note
.
nullifier
,
secret
:
note
.
secret
,
pathElements
:
pathElements
,
pathIndices
:
pathIndices
,
})
if
(
!
provingKey
)
provingKey
=
await
loadKey
();
if
(
!
groth16
)
groth16
=
await
buildGroth16
()
let
proofData
=
await
websnarkUtils
.
genWitnessAndProve
(
groth16
,
input
,
circuit
,
provingKey
)
const
{
proof
}
=
await
websnarkUtils
.
toSolidityInput
(
proofData
)
const
args
=
{
root
:
toFixedHex
(
input
.
root
),
nullifierHash
:
toFixedHex
(
input
.
nullifierHash
),
recipient
:
toFixedHex
(
input
.
recipient
,
20
),
relayer
:
toFixedHex
(
input
.
relayer
,
20
),
fee
:
toFixedHex
(
input
.
fee
),
refund
:
toFixedHex
(
input
.
refund
)
}
return
{
args
,
proof
}
}
public
async
simpleShift
(
amount
:
string
,
recipient
:
string
,
shifterAddress
:
string
,
cb
:
MethodCallback
=
null
):
Promise
<
any
>
{
const
{
methods
}
=
this
.
_getShifterContract
(
shifterAddress
)
return
methods
.
simpleShift
(
amount
,
recipient
).
send
({
from
:
recipient
,
gas
:
350000
},
cb
)
}
public
async
isDeposited
(
saveNote
:
string
,
shifterAddress
:
string
):
Promise
<
string
>
{
const
{
methods
}
=
this
.
_getShifterContract
(
shifterAddress
)
const
depositObject
=
parseSaveNote
(
saveNote
)
console
.
log
(
"
Commitment hex:
"
+
depositObject
.
commitmentHex
)
console
.
log
(
"
Is commitment deposited:
"
+
await
this
.
call
(
methods
.
commitments
(
depositObject
.
commitmentHex
)))
return
this
.
call
(
methods
.
commitments
(
depositObject
.
commitmentHex
))
}
public
async
isSpent
(
saveNote
:
string
,
shifterAddress
:
string
):
Promise
<
string
>
{
const
{
methods
}
=
this
.
_getShifterContract
(
shifterAddress
);
console
.
log
(
`The note being checked is:
${
saveNote
}
`
)
console
.
log
(
`Note spent:
${
await
this
.
call
(
methods
.
isSpent
(
parseSaveNote
(
saveNote
).
nullifierHex
))}
`
)
return
this
.
call
(
methods
.
isSpent
(
parseSaveNote
(
saveNote
).
nullifierHex
));
}
public
async
exactOutputSingle
(
params
:
string
[],
recipient
:
string
,
cb
:
MethodCallback
=
null
):
Promise
<
any
>
{
const
{
methods
}
=
this
.
_getSwapRouterContract
()
let
gas
=
await
methods
.
exactOutputSingle
(
params
).
estimateGas
({
from
:
recipient
},
cb
)
const
out
=
methods
.
exactOutputSingle
(
params
).
send
({
from
:
recipient
,
gas
:
gas
},
cb
)
return
out
}
public
async
exactOutputSingleCall
(
params
:
string
[],
recipient
:
string
,
cb
:
MethodCallback
=
null
):
Promise
<
any
>
{
const
{
methods
}
=
this
.
_getSwapRouterContract
()
const
out
=
methods
.
exactOutputSingle
(
params
).
call
({
from
:
recipient
},
cb
)
return
out
}
/*
struct QuoteExactOutputSingleParams {
address tokenIn;
address tokenOut;
uint256 amount;
uint24 fee;
uint160 sqrtPriceLimitX96;
}
*/
public
async
quoteExactOutputSingle
(
params
:
string
[],
user
:
string
,
cb
:
MethodCallback
=
null
):
Promise
<
any
>
{
const
{
methods
}
=
this
.
_getQuoterV2Contract
();
return
methods
.
quoteExactOutputSingle
(
params
).
call
({
from
:
user
});
}
public
async
quoteExactInputSingle
(
params
:
string
[],
user
:
string
,
cb
:
MethodCallback
=
null
):
Promise
<
any
>
{
const
{
methods
}
=
this
.
_getQuoterV2Contract
();
return
methods
.
quoteExactInputSingle
(
params
).
call
({
from
:
user
});
}
public
async
wethDeposit
(
amount
:
string
,
user
:
string
,
cb
:
MethodCallback
=
null
):
Promise
<
any
>
{
const
{
methods
}
=
this
.
_getWETH9Contract
()
return
methods
.
deposit
().
send
({
from
:
user
,
value
:
amount
},
cb
)
}
public
async
getChainlinkPriceETHUSD
(
amount
:
string
,
user
:
string
,
slippage
:
number
,
cb
:
MethodCallback
=
null
):
Promise
<
any
>
{
const
{
methods
}
=
this
.
_getChainlinkContract
(
"
0x5f4eC3Df9cbd43714FE2740f5E3616155c5b8419
"
)
//Mainnet ETHUSD Chainlink feed
let
chainlinkPrice
=
await
methods
.
latestAnswer
().
call
({
from
:
user
},
cb
)
const
chainlinkDecimals
=
await
methods
.
decimals
().
call
({
from
:
user
},
cb
)
let
amountBigInt
=
BigInt
(
amount
)
// Putting the rate in the denominator so we can get ETH in the numerator
let
exchangeRate
=
(
amountBigInt
*
BigInt
(
10
**
chainlinkDecimals
))
/
BigInt
(
chainlinkPrice
)
exchangeRate
=
exchangeRate
*
BigInt
(
100
+
slippage
)
/
BigInt
(
100
)
//Adds slippage amount to calculated price
return
exchangeRate
.
toString
()
}
public
async
getChainlinkPriceBTCETH
(
amount
:
string
,
user
:
string
,
slippage
:
number
,
cb
:
MethodCallback
=
null
):
Promise
<
any
>
{
const
{
methods
}
=
this
.
_getChainlinkContract
(
"
0xdeb288F737066589598e9214E782fa5A8eD689e8
"
)
//Mainnet BTCETH Chainlink feed
let
chainlinkPrice
=
await
methods
.
latestAnswer
().
call
({
from
:
user
},
cb
)
const
chainlinkDecimals
=
await
methods
.
decimals
().
call
({
from
:
user
},
cb
)
let
amountBigInt
=
BigInt
(
amount
)
// Rate goes in the numerator since BTCETH is the number of ETH per BTC
let
exchangeRate
=
(
amountBigInt
*
BigInt
(
chainlinkPrice
))
/
BigInt
(
10
**
chainlinkDecimals
)
exchangeRate
=
exchangeRate
*
BigInt
(
100
+
slippage
)
/
BigInt
(
100
)
//Adds slippage amount to calculated price
return
exchangeRate
.
toString
()
}
public
async
tokenSwap
(
user
:
string
,
cb
:
MethodCallback
=
null
):
Promise
<
any
>
{
const
{
methods
}
=
this
.
_getTokenSwapContract
()
const
gasEstimate
=
await
methods
.
upgrade
().
estimateGas
({
from
:
user
},
cb
)
return
methods
.
upgrade
().
send
({
from
:
user
,
gas
:
gasEstimate
},
cb
)
}
public
async
getV3IncentiveKey
(
user
:
string
):
Promise
<
any
>
{
const
{
methods
}
=
this
.
_getRewardContract
();
const
incentiveKey
=
await
methods
.
incentiveKey
().
call
({
from
:
user
});
return
incentiveKey
;
}
public
async
getIncentiveId
(
user
:
string
):
Promise
<
any
>
{
const
{
methods
}
=
this
.
_getRewardContract
();
const
incentiveKey
=
await
this
.
getV3IncentiveKey
(
user
);
const
incentiveId
=
await
methods
.
incentiveId
().
call
({
from
:
user
});
return
incentiveId
;
}
public
async
incentives
(
user
:
string
):
Promise
<
any
>
{
const
{
methods
}
=
this
.
_getV3StakerContract
();
const
incentiveId
=
await
this
.
getIncentiveId
(
user
);
const
incentives
=
await
methods
.
incentives
(
incentiveId
).
call
({
from
:
user
});
return
incentives
;
}
public
async
getAPY
(
user
:
string
):
Promise
<
any
>
{
const
incentives
=
await
this
.
incentives
(
user
);
const
incentiveKey
=
await
this
.
getV3IncentiveKey
(
user
);
const
interval
=
BigInt
(
incentiveKey
.
endTime
-
Math
.
ceil
(
Date
.
now
()
/
1000
));
const
yearInSeconds
=
BigInt
(
365
*
24
*
3600
);
//one year, in seconds
const
quoteXFTWETH
=
await
this
.
quoteExactInputSingle
([
TOKENS_MAP
[
"
XFT
"
].
contract
,
TOKENS_MAP
[
"
WETH
"
].
contract
,
incentives
.
totalRewardUnclaimed
.
toString
(),
"
3000
"
,
"
0
"
],
user
);
const
quote
=
BigInt
(
quoteXFTWETH
.
amountOut
.
toString
());
const
rewardsPerYearETH
=
quote
*
yearInSeconds
/
interval
;
const
ethBalPool
=
await
this
.
getBalance
(
incentiveKey
.
pool
,
TOKENS_MAP
[
"
WETH
"
].
contract
);
const
anonUSDBalPool
=
await
this
.
getBalance
(
incentiveKey
.
pool
,
TOKENS_MAP
[
"
anonUSD500
"
].
contract
);
const
anonUSDValue
=
await
this
.
getRequiredETH
(
anonUSDBalPool
.
toString
(),
user
);
const
poolValue
=
BigInt
(
anonUSDValue
.
toString
())
+
BigInt
(
ethBalPool
.
toString
());
const
poolValueFromWei
=
Number
(
fromWei
(
poolValue
.
toString
()));
const
rewardsFromWei
=
Number
(
fromWei
(
rewardsPerYearETH
.
toString
()));
const
apy
=
rewardsFromWei
*
100
/
poolValueFromWei
;
return
apy
.
toString
();
}
public
async
getRewardInfo
(
tokenId
:
string
,
user
:
string
):
Promise
<
any
>
{
const
{
methods
}
=
this
.
_getV3StakerContract
();
const
incentiveKey
=
await
this
.
getV3IncentiveKey
(
user
);
const
params
=
[
incentiveKey
.
rewardToken
,
incentiveKey
.
pool
,
incentiveKey
.
startTime
,
incentiveKey
.
endTime
,
incentiveKey
.
refundee
];
const
getRewardInfo
=
await
methods
.
getRewardInfo
(
params
,
tokenId
).
call
({
from
:
user
});
return
getRewardInfo
;
}
public
async
groupCommitment
(
address
:
string
,
commitmentsId
:
BigNumberValue
[],
cb
:
MethodCallback
=
null
,
):
Promise
<
any
>
{
const
{
assetEnum
,
commitment
,
pkSum
,
}
=
await
this
.
_http
.
post
<
any
>
(
this
.
apiUrl
(
'
group
'
),
{
address
,
commitmentsId
,
}).
toPromise
();
const
{
methods
}
=
this
.
_getBalanceContract
();
return
this
.
send
(
methods
.
groupCommitment
(
commitmentsId
,
assetEnum
,
commitment
,
pkSum
),
cb
);
}
public
async
groupCommitmentsSpent
(
address
:
string
,
hashTx
:
string
,
commitmentsId
:
BigNumberValue
[],
cb
:
MethodCallback
=
null
,
):
Promise
<
any
>
{
return
await
this
.
_http
.
post
<
any
>
(
this
.
apiUrl
(
'
group
'
,
'
spent
'
),
{
address
,
hashTx
,
commitmentsId
,
}).
toPromise
();
}
public
async
xftBalance
(
address
:
string
):
Promise
<
string
>
{
const
{
methods
}
=
this
.
_getXFTContract
();
return
this
.
call
(
methods
.
balanceOf
(
address
));
}
public
async
usdBalance
(
address
:
string
):
Promise
<
string
>
{
const
{
methods
}
=
this
.
_getUSDContract
();
return
this
.
call
(
methods
.
balanceOf
(
address
));
}
public
async
getBalance
(
userAddress
:
string
,
tokenAddress
:
string
,
cb
:
MethodCallback
=
null
):
Promise
<
string
>
{
const
{
methods
}
=
this
.
_getTokenContract
(
tokenAddress
)
return
methods
.
balanceOf
(
userAddress
).
call
({
from
:
userAddress
},
cb
)
}
public
async
getLatestPrice
(
aggregator
:
number
):
Promise
<
{
price
:
string
,
decimals
:
number
}
>
{
const
{
methods
}
=
this
.
_getPriceContract
();
const
latestPrice
=
0
;
const
[
price
,
decimals
]
=
Object
.
values
(
latestPrice
);
return
{
price
,
decimals
:
Number
(
decimals
)
};
}
public
async
getRequiredETH
(
amount
:
string
,
account
:
string
):
Promise
<
string
>
{
const
{
methods
}
=
this
.
_getRewardContract
();
return
methods
.
getETHAmount
(
amount
).
call
({
from
:
account
});
}
public
async
shift
(
amount
:
string
,
ether
:
string
,
account
:
string
,
cb
:
MethodCallback
=
null
):
Promise
<
void
>
{
const
{
methods
}
=
this
.
_getRewardContract
();
await
methods
.
shift
(
amount
).
send
({
from
:
account
,
value
:
ether
},
cb
);
}
public
async
addLiquidity
(
amount
:
string
,
ether
:
string
,
account
:
string
,
cb
:
MethodCallback
=
null
):
Promise
<
void
>
{
const
{
methods
}
=
this
.
_getRewardUnlockedContract
();
await
methods
.
addLiquidity
(
amount
).
send
({
from
:
account
,
value
:
ether
},
cb
);
}
public
async
liquidityUnlocked
(
user
:
string
,
cb
:
MethodCallback
=
null
):
Promise
<
boolean
>
{
const
{
methods
}
=
this
.
_getRewardContract
();
const
expiry
=
await
methods
.
expiry
().
call
({
from
:
user
});
const
blockNumber
=
await
this
.
_walletService
.
web3
.
eth
.
getBlockNumber
();
return
(
Number
(
blockNumber
)
>
Number
(
expiry
));
}
//withdraw the token from the contract
public
async
liquidityWithdraw
(
tokenId
:
string
,
account
:
string
):
Promise
<
void
>
{
const
{
methods
}
=
this
.
_getRewardContract
();
methods
.
withdraw
(
tokenId
).
send
({
from
:
account
});
}
public
async
liquidityWithdrawUnlocked
(
tokenId
:
string
,
account
:
string
):
Promise
<
void
>
{
const
{
methods
}
=
this
.
_getRewardUnlockedContract
();
methods
.
withdraw
(
tokenId
).
send
({
from
:
account
});
}
// Get all the staked tokens in the contract that belong to the account
public
async
queryTokenIds
(
accountAddress
:
string
):
Promise
<
any
[]
>
{
const
contract
=
this
.
_getRewardContract
();
const
stakerContract
=
this
.
_getV3StakerContract
();
const
incentiveKey
=
await
this
.
getV3IncentiveKey
(
accountAddress
);
const
params
=
[
incentiveKey
.
rewardToken
,
incentiveKey
.
pool
,
incentiveKey
.
startTime
,
incentiveKey
.
endTime
,
incentiveKey
.
refundee
];
let
events
:
any
[]
=
[];
contract
.
events
.
NFT_LOCKED
({
filter
:
{
owner
:
accountAddress
},
fromBlock
:
0
,
},
async
function
(
error
:
any
,
event
:
EventData
){
const
deposit
=
await
contract
.
methods
.
deposits
(
event
.
returnValues
[
'
tokenId
'
]).
call
();
if
(
deposit
.
liquidity
!=
0
){
events
.
push
({
token
:
event
.
returnValues
[
'
tokenId
'
],
locked
:
true
,
reward
:
fromWei
((
await
stakerContract
.
methods
.
getRewardInfo
(
params
,
event
.
returnValues
[
'
tokenId
'
]).
call
({
from
:
accountAddress
})).
reward
)
});
}
});
return
events
;
}
// Get all the staked tokens in the contract that belong to the account
public
async
queryTokenIdsUnlocked
(
accountAddress
:
string
):
Promise
<
any
[]
>
{
const
contract
=
this
.
_getRewardUnlockedContract
();
const
stakerContract
=
this
.
_getV3StakerContract
();
const
incentiveKey
=
await
this
.
getV3IncentiveKey
(
accountAddress
);
const
params
=
[
incentiveKey
.
rewardToken
,
incentiveKey
.
pool
,
incentiveKey
.
startTime
,
incentiveKey
.
endTime
,
incentiveKey
.
refundee
];
let
events
:
any
[]
=
[];
contract
.
events
.
NFT_LOCKED
({
filter
:
{
owner
:
accountAddress
},
fromBlock
:
0
,
},
async
function
(
error
:
any
,
event
:
EventData
){
const
deposit
=
await
contract
.
methods
.
deposits
(
event
.
returnValues
[
'
tokenId
'
]).
call
();
if
(
deposit
.
liquidity
!=
0
){
events
.
push
({
token
:
event
.
returnValues
[
'
tokenId
'
],
locked
:
false
,
reward
:
fromWei
((
await
stakerContract
.
methods
.
getRewardInfo
(
params
,
event
.
returnValues
[
'
tokenId
'
]).
call
({
from
:
accountAddress
})).
reward
)
});
}
});
return
events
;
}
public
download
(
note
:
string
,
commitment
:
string
,
shifter
:
string
):
void
{
let
receipt
=
{
"
shifter
"
:
shifter
,
"
commitment
"
:
commitment
,
"
note
"
:
note
}
var
file
=
new
Blob
([
JSON
.
stringify
(
receipt
)],
{
type
:
'
.txt
'
});
var
a
=
document
.
createElement
(
"
a
"
),
url
=
URL
.
createObjectURL
(
file
);
a
.
href
=
url
;
const
timestamp
=
Date
.
now
();
a
.
download
=
`xft-note-
${
timestamp
}
`
document
.
body
.
appendChild
(
a
);
a
.
click
();
setTimeout
(
function
()
{
document
.
body
.
removeChild
(
a
);
window
.
URL
.
revokeObjectURL
(
url
);
},
0
);
}
private
_getXFTContract
():
TokenContract
{
const
XFT
=
Object
.
values
(
TOKENS_MAP
).
find
(
value
=>
value
[
"
zkSymbol
"
]
===
"
XFT
"
)
const
address
=
XFT
[
"
contract
"
]
return
this
.
_getContractInstance
(
AUSD_CONTRACT_ABI
,
address
);
}
private
_getUSDContract
():
TokenContract
{
const
anonUSD
=
Object
.
values
(
TOKENS_MAP
).
find
(
value
=>
value
[
"
name
"
]
===
"
anonUSD
"
)
const
address
=
anonUSD
[
"
contract
"
]
return
this
.
_getContractInstance
(
AUSD_CONTRACT_ABI
,
address
)
}
private
_getTokenContract
(
address
:
string
):
TokenContract
{
return
this
.
_getContractInstance
(
AUSD_CONTRACT_ABI
,
address
)
}
private
_getPriceContract
():
PriceContract
{
return
this
.
_getContractInstance
(
PRICE_CONTRACT_ABI
,
environment
.
priceContractAddress
);
}
private
_getBalanceContract
():
BalanceContract
{
return
this
.
_getContractInstance
(
BALANCE_CONTRACT_ABI
,
environment
.
balanceContractAddress
);
}
private
_getShifterContract
(
addr
:
string
=
null
):
ShifterContract
{
return
this
.
_getContractInstance
(
SHIFTER_CONTRACT_ABI
,
addr
);
}
private
_getStorageContract
():
StorageContract
{
return
this
.
_getContractInstance
(
STORAGE_CONTRACT_ABI
,
environment
.
storageContractAddress
);
}
private
_getSwapRouterContract
():
SwapRouterContract
{
return
this
.
_getContractInstance
(
SWAPROUTER_CONTRACT_ABI
,
"
0xE592427A0AEce92De3Edee1F18E0157C05861564
"
);
// Hardcoded by Uniswap
}
private
_getV3StakerContract
():
V3StakerContract
{
return
this
.
_getContractInstance
(
V3STAKER_CONTRACT_ABI
,
"
0xe34139463bA50bD61336E0c446Bd8C0867c6fE65
"
);
//Hardcoded by Uniswap
}
private
_getWETH9Contract
():
Weth9Contract
{
return
this
.
_getContractInstance
(
WETH9_CONTRACT_ABI
,
"
0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2
"
)
}
private
_getChainlinkContract
(
address
:
string
):
ChainlinkContract
{
return
this
.
_getContractInstance
(
CHAINLINK_CONTRACT_ABI
,
address
)
}
private
_getTokenSwapContract
():
TokenSwapContract
{
return
this
.
_getContractInstance
(
TOKENSWAP_CONTRACT_ABI
,
environment
.
tokenSwapAddress
)
}
private
_getRewardContract
():
RewardContract
{
return
this
.
_getContractInstance
(
REWARDER_contract_abi
,
environment
.
rewarderAddress
);
}
private
_getRewardUnlockedContract
():
RewardUnlockedContract
{
return
this
.
_getContractInstance
(
REWARDERUNLOCKED_CONTRACT_ABI
,
environment
.
rewarderUnlockedAddress
)
}
private
_getOracleContract
():
OracleContract
{
return
this
.
_getContractInstance
(
ORACLE_CONTRACT_ABI
,
environment
.
oracleAddress
);
}
private
_getQuoterV2Contract
():
QuoterV2Contract
{
return
this
.
_getContractInstance
(
QUOTERV2_CONTRACT_ABI
,
"
0x61fFE014bA17989E743c5F6cB21bF9697530B21e
"
);
//Hardcoded uniswap deployment
}
private
_getContractInstance
<
T
extends
Contract
>
(
abi
:
AbiItem
[],
address
:
string
):
T
{
if
(
!
isAddress
(
address
))
{
throw
new
Error
(
'
Contract address is not valid
'
);
}
const
contractInstance
=
new
this
.
_walletService
.
web3
.
eth
.
Contract
(
abi
,
address
);
CONTRACT_MAP
.
set
(
address
,
contractInstance
);
return
contractInstance
as
T
;
}
protected
override
apiUrl
(...
path
:
string
[]):
string
{
let
url
=
`
${
super
.
apiUrl
()}
`
;
if
(
path
&&
Array
.
isArray
(
path
))
{
url
=
path
.
reduce
((
cur
,
prev
)
=>
{
cur
+=
`/
${
prev
}
`
;
return
cur
;
},
url
);
}
return
url
;
}
}
\ No newline at end of file
This diff is collapsed.
Click to expand it.
Prev
1
2
3
4
5
6
7
…
10
Next
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
Menu
Projects
Groups
Snippets
Help