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/support moonbeam #18

Merged
merged 11 commits into from
Apr 24, 2022
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.4.0",
"version": "0.4.1",
"main": "./cjs/index.js",
"module": "./esm/index.js",
"files": [
Expand Down
21 changes: 21 additions & 0 deletions src/constants/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
export const NATIVE_CHAIN_TOKENS = [{
chainType: 'ethereum',
network: 'mainnet',
chainId: 1,
nativeSymbol: 'eth'
}, {
chainType: 'ethereum',
network: 'kovan',
chainId: 42,
nativeSymbol: 'eth'
}, {
chainType: 'moon',
network: 'moonbeam',
chainId: 1284,
nativeSymbol: 'glmr'
}, {
chainType: 'moon',
network: 'moonbase-alphanet',
chainId: 1287,
nativeSymbol: 'dev'
}]
20 changes: 13 additions & 7 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import {
Config, EverpayInfo, EverpayBase, BalanceParams, BalancesParams, DepositParams, SwapInfo,
SendEverpayTxResult, TransferParams, WithdrawParams, EverpayTxWithoutSig, EverpayAction, BundleData,
SwapOrder, SwapPriceParams, SwapPriceResult, FeeItem, ChainType,
BalanceItem, TxsParams, TxsByAccountParams, TxsResult, EverpayTransaction, Token, EthereumTransaction, ArweaveTransaction, ExpressInfo, CachedInfo, InternalTransferItem, BundleDataWithSigs, BundleParams
BalanceItem, TxsParams, TxsByAccountParams, TxsResult, EverpayTransaction, Token, EthereumTransaction, ArweaveTransaction, ExpressInfo, CachedInfo, InternalTransferItem, BundleDataWithSigs, BundleParams, EverpayTx
} from './types'
import { swapParamsClientToServer, swapParamsServerToClient } from './utils/swap'

Expand All @@ -20,7 +20,8 @@ class Everpay extends EverpayBase {
super()
this._config = {
...config,
account: config?.account ?? ''
account: config?.account ?? '',
chainType: config?.chainType ?? ChainType.ethereum
}
this._apiHost = getEverpayHost(config?.debug)
this._expressHost = getExpressHost(config?.debug)
Expand Down Expand Up @@ -169,15 +170,15 @@ class Everpay extends EverpayBase {
const { amount, symbol } = params
const from = this._config.account
const token = getTokenBySymbol(symbol, this._cachedInfo?.everpay?.value.tokenList) as Token
const chainType = this._config.chainType
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) {
if (isArweaveChainPSTMode(token) && chainType === ChainType.arweave && parseInt(amount) !== +amount) {
throw new Error(ERRORS.DEPOSIT_ARWEAVE_PST_MUST_BE_INTEGER)
}

const chainDecimal = getChainDecimalByChainType(token, accountChainType)
const chainDecimal = getChainDecimalByChainType(token, chainType as ChainType)
const value = utils.parseUnits(toBN(amount).toString(), chainDecimal)

return await transferAsync(this._config, this._cachedInfo.everpay?.value as EverpayInfo, {
Expand Down Expand Up @@ -305,13 +306,18 @@ class Everpay extends EverpayBase {
return getEverpayTxMessage(everpayTxWithoutSig)
}

async sendEverpayTx (everpayTxWithoutSig: EverpayTxWithoutSig): Promise<SendEverpayTxResult> {
async signedEverpayTx (everpayTxWithoutSig: EverpayTxWithoutSig): Promise<{everpayTx: EverpayTx, everHash: string}> {
const messageData = getEverpayTxMessage(everpayTxWithoutSig)
const { everHash, sig } = await signMessageAsync(this._config, messageData)
const { sig, everHash } = await signMessageAsync(this._config, messageData)
const everpayTx = {
...everpayTxWithoutSig,
sig
}
return { everpayTx, everHash }
}

async sendEverpayTx (everpayTxWithoutSig: EverpayTxWithoutSig): Promise<SendEverpayTxResult> {
const { everpayTx, everHash } = await this.signedEverpayTx(everpayTxWithoutSig)
const postEverpayTxResult = await postTx(this._apiHost, everpayTx)
return {
...postEverpayTxResult,
Expand Down
2 changes: 1 addition & 1 deletion src/lib/arweave.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ const signMessageAsync = async (arJWK: ArJWK, address: string, everHash: string)
return `${signatureB64url},${arOwner}`
}

const transferAsync = async (arJWK: ArJWK, {
const transferAsync = async (arJWK: ArJWK, chainType: ChainType, {
symbol,
token,
from,
Expand Down
10 changes: 7 additions & 3 deletions src/lib/ethereum.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { TransferAsyncParams } from './interface'
import erc20Abi from '../constants/abi/erc20'
import { getTokenAddrByChainType } from '../utils/util'
import { ChainType, EthereumTransaction } from '../types'
import { NATIVE_CHAIN_TOKENS } from '../constants'

// 参考自 zkSync
// https://github.com/WalletConnect/walletconnect-monorepo/issues/347#issuecomment-880553018
Expand All @@ -27,17 +28,20 @@ const signMessageAsync = async (ethConnectedSigner: Signer, address: string, mes
}
}

const transferAsync = async (ethConnectedSigner: Signer, {
const transferAsync = async (ethConnectedSigner: Signer, chainType: ChainType, {
symbol,
token,
from,
to,
value
}: TransferAsyncParams): Promise<EthereumTransaction> => {
let transactionResponse: EthereumTransaction
const foundNative = NATIVE_CHAIN_TOKENS.find(t => {
return t.chainType === chainType && t.nativeSymbol === symbol.toLowerCase()
})

// TODO: check balance
if (symbol.toLowerCase() === 'eth') {
if (foundNative != null) {
const transactionRequest = {
from: from.toLowerCase(),
to: to?.toLowerCase(),
Expand All @@ -46,7 +50,7 @@ const transferAsync = async (ethConnectedSigner: Signer, {
}
transactionResponse = await ethConnectedSigner.sendTransaction(transactionRequest)
} else {
const tokenID = getTokenAddrByChainType(token, ChainType.ethereum)
const tokenID = getTokenAddrByChainType(token, chainType)
const erc20RW = new Contract(tokenID.toLowerCase(), erc20Abi, ethConnectedSigner)
transactionResponse = await erc20RW.transfer(to, value, {
gasLimit: 100000
Expand Down
24 changes: 12 additions & 12 deletions src/lib/sign.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,16 @@ import { ArJWK, ChainType, Config, EverpayInfo, EverpayTxWithoutSig, EthereumTra
import { checkSignConfig } from '../utils/check'
import { Signer } from '@ethersproject/abstract-signer'
import { ERRORS } from '../utils/errors'
import { getAccountChainType } from '../utils/util'
import hashPersonalMessage from './hashPersonalMessage'

const getDepositAddr = (info: EverpayInfo, accountChainType: ChainType): string => {
if (accountChainType === ChainType.ethereum) {
return info?.ethLocker
return info?.lockers.ethereum
} else if (accountChainType === ChainType.arweave) {
// AR 大小写敏感
return info?.arLocker
return info?.lockers.arweave
} else if (accountChainType === ChainType.moon) {
return info?.lockers.moon
}
throw new Error(ERRORS.INVALID_ACCOUNT_TYPE)
}
Expand All @@ -39,13 +40,13 @@ export const getEverpayTxMessage = (everpayTxWithoutSig: EverpayTxWithoutSig): s

export const signMessageAsync = async (config: Config, messageData: string): Promise<SignMessageAsyncResult> => {
const from = config.account as string
const accountChainType = getAccountChainType(from)
const accountChainType = config.chainType as ChainType
const personalMsgHashBuffer = hashPersonalMessage(Buffer.from(messageData))
const personalMsgHex = `0x${personalMsgHashBuffer.toString('hex')}`
let sig = ''
checkSignConfig(accountChainType, config)

if (accountChainType === ChainType.ethereum) {
if ([ChainType.ethereum, ChainType.moon].includes(accountChainType)) {
sig = await ethereumLib.signMessageAsync(config.ethConnectedSigner as Signer, from, messageData)
} else if (accountChainType === ChainType.arweave) {
sig = await arweaveLib.signMessageAsync(config.arJWK as ArJWK, from, personalMsgHex)
Expand All @@ -60,16 +61,15 @@ export const transferAsync = async (
info: EverpayInfo,
params: TransferAsyncParams
): Promise<EthereumTransaction | ArweaveTransaction> => {
const accountChainType = getAccountChainType(params.from)
checkSignConfig(accountChainType, config)
checkSignConfig(config.chainType as ChainType, config)

const to = getDepositAddr(info, accountChainType)
const to = getDepositAddr(info, config.chainType as ChainType)
const paramsMergedTo = { ...params, to }

if (accountChainType === ChainType.ethereum) {
return await ethereumLib.transferAsync(config.ethConnectedSigner as Signer, paramsMergedTo)
} else if (accountChainType === ChainType.arweave) {
return await arweaveLib.transferAsync(config.arJWK as ArJWK, paramsMergedTo)
if ([ChainType.ethereum, ChainType.moon].includes(config.chainType as ChainType)) {
return await ethereumLib.transferAsync(config.ethConnectedSigner as Signer, config.chainType as ChainType, paramsMergedTo)
} else if (config.chainType as ChainType === ChainType.arweave) {
return await arweaveLib.transferAsync(config.arJWK as ArJWK, config.chainType as ChainType, paramsMergedTo)
}

throw new Error(ERRORS.INVALID_ACCOUNT_TYPE)
Expand Down
9 changes: 6 additions & 3 deletions src/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ import { TransactionInterface as ArweaveTransaction } from 'arweave/node/lib/tra

export enum ChainType {
ethereum = 'ethereum',
arweave = 'arweave'
moon = 'moon',
arweave = 'arweave',
}

export type ArJWK = JWKInterface | 'use_wallet'
Expand All @@ -16,6 +17,7 @@ export { EthereumTransaction, ArweaveTransaction }
export interface Config {
debug?: boolean
account?: string
chainType?: ChainType
ethConnectedSigner?: Signer
arJWK?: ArJWK
}
Expand Down Expand Up @@ -51,8 +53,9 @@ export interface FeeItem {
}

export interface EverpayInfo {
ethLocker: string
arLocker: string
lockers: {
[propName: string]: string
}
ethChainID: string
feeRecipient: string
owner: string
Expand Down
28 changes: 28 additions & 0 deletions test/deposit.moonbase.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import Everpay, { ChainType } from '../src/index'
import { ethWalletHasUSDT } from './constants/wallet'
import { ethers } from 'ethers'

const providerURL = 'https://rpc.api.moonbase.moonbeam.network'
// Define Provider
const provider = new ethers.providers.StaticJsonRpcProvider(providerURL, {
chainId: 1287,
name: 'moonbase-alphanet'
})
const signer = new ethers.Wallet(ethWalletHasUSDT.privateKey, provider)

const everpay = new Everpay({
account: ethWalletHasUSDT.address,
chainType: ChainType.moon,
ethConnectedSigner: signer,
debug: true
})

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