Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/PST token decimals #9

Merged
merged 5 commits into from
Dec 22, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "everpay",
"version": "0.2.1",
"version": "0.3.0",
"main": "./cjs/index.js",
"module": "./esm/index.js",
"files": [
Expand Down
31 changes: 23 additions & 8 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import { getEverpayTxMessage, signMessageAsync, transferAsync } from './lib/sign'
import { getSwapInfo, getEverpayBalance, getEverpayBalances, getEverpayInfo, getEverpayTransaction, getEverpayTransactions, getExpressInfo, getMintdEverpayTransactionByChainTxHash, postTx, getSwapPrice, placeSwapOrder, getFees, getFee } from './api'
import { everpayTxVersion, getExpressHost, getEverpayHost, getSwapHost } from './config'
import { getTimestamp, getTokenBySymbol, toBN, getAccountChainType, fromDecimalToUnit, genTokenTag, matchTokenTag, genExpressData, fromUnitToDecimalBN, genBundleData, getTokenBurnFeeByChainType, getChainDecimalByChainType } from './utils/util'
import { getTimestamp, getTokenBySymbol, toBN, getAccountChainType, fromDecimalToUnit, genTokenTag, matchTokenTag, genExpressData, fromUnitToDecimalBN, genBundleData, getTokenBurnFeeByChainType, getChainDecimalByChainType, isArweaveChainPSTMode } from './utils/util'
import { GetEverpayBalanceParams, GetEverpayBalancesParams, GetEverpayTransactionsParams } from './types/api'
import { checkParams } from './utils/check'
import { ERRORS } from './utils/errors'
import { utils } from 'ethers'
import {
Config, EverpayInfo, EverpayBase, BalanceParams, BalancesParams, DepositParams, SwapInfo,
SendEverpayTxResult, TransferParams, WithdrawParams, EverpayTxWithoutSig, EverpayAction, BundleData,
SwapOrder, SwapPriceParams, SwapPriceResult, FeeItem,
SwapOrder, SwapPriceParams, SwapPriceResult, FeeItem, ChainType,
BalanceItem, TxsParams, TxsByAccountParams, TxsResult, EverpayTransaction, Token, EthereumTransaction, ArweaveTransaction, ExpressInfo, CachedInfo, InternalTransferItem, BundleDataWithSigs, BundleParams
} from './types'
import { swapParamsClientToServer, swapParamsServerToClient } from './utils/swap'
Expand Down Expand Up @@ -167,12 +167,18 @@ class Everpay extends EverpayBase {
async deposit (params: DepositParams): Promise<EthereumTransaction | ArweaveTransaction> {
await this.info()
const { amount, symbol } = params
const from = this._config.account
const token = getTokenBySymbol(symbol, this._cachedInfo?.everpay?.value.tokenList) as Token
checkParams({ account: from, symbol, token, amount })
const accountChainType = getAccountChainType(this._config.account as string)

// arweave 上的 PST 充值必须是整数
if (isArweaveChainPSTMode(token) && accountChainType === ChainType.arweave && parseInt(amount) !== +amount) {
throw new Error(ERRORS.DEPOSIT_ARWEAVE_PST_MUST_BE_INTEGER)
}

const chainDecimal = getChainDecimalByChainType(token, accountChainType)
const value = utils.parseUnits(toBN(amount).toString(), chainDecimal)
const from = this._config.account
checkParams({ account: from, symbol, token, amount })

return await transferAsync(this._config, this._cachedInfo.everpay?.value as EverpayInfo, {
symbol,
Expand All @@ -182,6 +188,7 @@ class Everpay extends EverpayBase {
})
}

// amount 为实际收款数量
async getEverpayTxWithoutSig (
type: 'transfer' | 'withdraw' | 'bundle',
params: TransferParams | WithdrawParams | BundleParams
Expand Down Expand Up @@ -210,7 +217,15 @@ class Everpay extends EverpayBase {
} else if (type === 'withdraw') {
checkParams({ amount })
const chainType = (params as WithdrawParams).chainType

// PST 提现到 arweave 网络必须是整数
if (isArweaveChainPSTMode(token) && chainType === ChainType.arweave && parseInt(amount) !== +amount) {
throw new Error(ERRORS.PST_WITHDARW_TO_ARWEAVE_MUST_BE_INTEGER)
}

const tokenChainType = token?.chainType as string
const balance = await this.balance({ symbol })
const decimalBalanceBN = fromUnitToDecimalBN(balance, token?.decimals ?? 0)

// 快速提现
if (quickMode === true) {
Expand All @@ -232,7 +247,7 @@ class Everpay extends EverpayBase {
// 快速提现的 amount 为全部数量
decimalOperateAmountBN = fromUnitToDecimalBN(amount, token?.decimals ?? 0)

if (decimalOperateAmountBN.lte(quickWithdrawFeeBN)) {
if (decimalOperateAmountBN.plus(quickWithdrawFeeBN).gt(decimalBalanceBN)) {
throw new Error(ERRORS.WITHDRAW_AMOUNT_LESS_THAN_FEE)
}

Expand Down Expand Up @@ -264,9 +279,9 @@ class Everpay extends EverpayBase {
const targetChainType = chainType
data = data !== undefined ? { ...data, targetChainType } : { targetChainType }
}
decimalOperateAmountBN = fromUnitToDecimalBN(amount, token?.decimals ?? 0).minus(decimalFeeBN)
// 普通提现的 amount 为实际到账数量
if (decimalOperateAmountBN.lte(0)) {
decimalOperateAmountBN = fromUnitToDecimalBN(amount, token?.decimals ?? 0)

if (decimalOperateAmountBN.plus(decimalFeeBN).gt(decimalBalanceBN)) {
throw new Error(ERRORS.WITHDRAW_AMOUNT_LESS_THAN_FEE)
}
}
Expand Down
4 changes: 3 additions & 1 deletion src/utils/errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,7 @@ export enum ERRORS {
UNSUPPORTED_TOKEN_SWAP = 'UNSUPPORTED_TOKEN_SWAP',
WITHDRAW_AMOUNT_LESS_THAN_FEE = 'WITHDRAW_AMOUNT_LESS_THAN_FEE',
INSUFFICIENT_QUICK_WITHDRAWAL_AMOUNT = 'INSUFFICIENT_QUICK_WITHDRAWAL_AMOUNT',
WITHDRAW_TOKEN_NOT_SUPPORT_QUICK_MODE = 'WITHDRAW_TOKEN_NOT_SUPPORT_QUICK_MODE'
WITHDRAW_TOKEN_NOT_SUPPORT_QUICK_MODE = 'WITHDRAW_TOKEN_NOT_SUPPORT_QUICK_MODE',
DEPOSIT_ARWEAVE_PST_MUST_BE_INTEGER = 'DEPOSIT_ARWEAVE_PST_MUST_BE_INTEGER',
PST_WITHDARW_TO_ARWEAVE_MUST_BE_INTEGER = 'PST_WITHDARW_TO_ARWEAVE_MUST_BE_INTEGER'
}
5 changes: 5 additions & 0 deletions src/utils/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,11 @@ const isArweaveAddress = (address: string): boolean => {
return isString(address) && address.length === 43 && address.search(/[a-z0-9A-Z_-]{43}/g) === 0
}

export const isArweaveChainPSTMode = (token?: Token): boolean => {
if (token == null) return false
return token.chainType.includes(ChainType.arweave) && token.symbol.toUpperCase() !== 'AR'
}

export const getAccountChainType = (from: string): ChainType => {
if (isEthereumAddress(from)) {
return ChainType.ethereum
Expand Down
50 changes: 50 additions & 0 deletions test/deposit.pst.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import Everpay from '../src/index'
import { ethWalletHasUSDT, arWallet2 } from './constants/wallet'
import { ArweaveTransaction } from '../src/types'
import { ethers } from 'ethers'

const provider = new ethers.providers.InfuraProvider('kovan')
const signer = new ethers.Wallet(ethWalletHasUSDT.privateKey, provider)

const everpayEthereumMode = new Everpay({
account: ethWalletHasUSDT.address,
ethConnectedSigner: signer,
debug: true
})

test(`check ${ethWalletHasUSDT.address} deposit vrt`, async () => {
return await everpayEthereumMode.deposit({
symbol: 'vrt',
amount: '0.000000001'
}).then(ethTx => {
console.log('ethTx', ethTx)
expect(ethTx).toBeTruthy()
})
})

const everpayARMode = new Everpay({
account: arWallet2.address,
arJWK: arWallet2.jwk,
debug: true
})

test(`check ${arWallet2.address} deposit VRT`, async () => {
return await everpayARMode.deposit({
symbol: 'vrt',
amount: '1'
}).then((arTx) => {
console.log('arTx', arTx as ArweaveTransaction)
expect((arTx as ArweaveTransaction).id).toBeTruthy()
})
})

test(`check ${arWallet2.address} deposit VRT failed`, async () => {
await expect(
everpayARMode.deposit({
symbol: 'vrt',
amount: '0.1'
})
)
.rejects
.toThrow('DEPOSIT_ARWEAVE_PST_MUST_BE_INTEGER')
})
19 changes: 19 additions & 0 deletions test/transfer.pst.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import Everpay from '../src/index'
import { arWallet2, ethWalletHasUSDT } from './constants/wallet'

test(`${arWallet2.address} withdraw ar to ${arWallet2.address}`, async () => {
const everpay = new Everpay({
account: arWallet2.address,
arJWK: arWallet2.jwk,
debug: true
})

return await everpay.transfer({
symbol: 'VRT',
amount: '0.000010001',
to: ethWalletHasUSDT.address
}).then(withdrawResult => {
console.log('withdrawResult', withdrawResult)
expect(withdrawResult.status).toBe('ok')
})
})
56 changes: 56 additions & 0 deletions test/withdraw.pst.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import Everpay from '../src/index'
import { arWallet2, ethWalletHasUSDT } from './constants/wallet'
import { ChainType } from '../src/types'

test(`${arWallet2.address} withdraw vrt to ${arWallet2.address}`, async () => {
const everpay = new Everpay({
account: arWallet2.address,
arJWK: arWallet2.jwk,
debug: true
})

return await everpay.withdraw({
chainType: ChainType.arweave,
symbol: 'vrt',
amount: '1',
to: arWallet2.address
}).then(withdrawResult => {
console.log('withdrawResult', withdrawResult)
expect(withdrawResult.status).toBe('ok')
})
})

test(`check ${arWallet2.address} deposit VRT failed`, async () => {
const everpay = new Everpay({
account: arWallet2.address,
arJWK: arWallet2.jwk,
debug: true
})
await expect(
everpay.withdraw({
chainType: ChainType.arweave,
symbol: 'vrt',
amount: '0.1'
})
)
.rejects
.toThrow('PST_WITHDARW_TO_ARWEAVE_MUST_BE_INTEGER')
})

test(`${arWallet2.address} withdraw ar to ethereum address ${ethWalletHasUSDT.address}`, async () => {
const everpay = new Everpay({
account: arWallet2.address,
arJWK: arWallet2.jwk,
debug: true
})

return await everpay.withdraw({
chainType: ChainType.ethereum,
symbol: 'vrt',
amount: '0.000010001',
to: ethWalletHasUSDT.address
}).then(withdrawResult => {
console.log('withdrawResult', withdrawResult)
expect(withdrawResult.status).toBe('ok')
})
})