mirror of
https://github.com/tornadocash/provider.git
synced 2024-11-21 17:26:51 +01:00
fix: update
This commit is contained in:
commit
2f0fbf56f0
10
.eslintrc.js
Normal file
10
.eslintrc.js
Normal file
@ -0,0 +1,10 @@
|
||||
module.exports = {
|
||||
root: true,
|
||||
parserOptions: {
|
||||
parser: 'babel-eslint',
|
||||
sourceType: 'module'
|
||||
},
|
||||
extends: [
|
||||
'@nuxtjs'
|
||||
]
|
||||
}
|
5
.idea/codeStyles/codeStyleConfig.xml
Normal file
5
.idea/codeStyles/codeStyleConfig.xml
Normal file
@ -0,0 +1,5 @@
|
||||
<component name="ProjectCodeStyleConfiguration">
|
||||
<state>
|
||||
<option name="PREFERRED_PROJECT_CODE_STYLE" value="Default" />
|
||||
</state>
|
||||
</component>
|
8
.idea/modules.xml
Normal file
8
.idea/modules.xml
Normal file
@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/provider.iml" filepath="$PROJECT_DIR$/.idea/provider.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
12
.idea/provider.iml
Normal file
12
.idea/provider.iml
Normal file
@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="WEB_MODULE" version="4">
|
||||
<component name="NewModuleRootManager">
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<excludeFolder url="file://$MODULE_DIR$/.tmp" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/temp" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/tmp" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
6
.idea/vcs.xml
Normal file
6
.idea/vcs.xml
Normal file
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
55
.idea/workspace.xml
Normal file
55
.idea/workspace.xml
Normal file
@ -0,0 +1,55 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ChangeListManager">
|
||||
<list default="true" id="c0d2cb1a-45f7-4ae6-a3c7-4649a212b52b" name="Default Changelist" comment="">
|
||||
<change afterPath="$PROJECT_DIR$/.eslintrc.js" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/babel.config.js" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/lib/module.js" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/lib/plugin.js" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/nuxt.config.js" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/package.json" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/types/index.d.ts" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/types/vue.d.ts" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/yarn.lock" afterDir="false" />
|
||||
</list>
|
||||
<option name="SHOW_DIALOG" value="false" />
|
||||
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
||||
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
|
||||
<option name="LAST_RESOLUTION" value="IGNORE" />
|
||||
</component>
|
||||
<component name="Git.Settings">
|
||||
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" />
|
||||
</component>
|
||||
<component name="ProjectId" id="1jsuBfSpRzpsyM93w9WXPUOUpVQ" />
|
||||
<component name="ProjectViewState">
|
||||
<option name="hideEmptyMiddlePackages" value="true" />
|
||||
<option name="showLibraryContents" value="true" />
|
||||
</component>
|
||||
<component name="PropertiesComponent">
|
||||
<property name="RunOnceActivity.OpenProjectViewOnStart" value="true" />
|
||||
<property name="last_opened_file_path" value="$PROJECT_DIR$" />
|
||||
<property name="nodejs_package_manager_path" value="yarn" />
|
||||
<property name="ts.external.directory.path" value="$APPLICATION_HOME_DIR$/plugins/JavaScriptLanguage/jsLanguageServicesImpl/external" />
|
||||
<property name="vue.rearranger.settings.migration" value="true" />
|
||||
</component>
|
||||
<component name="RecentsManager">
|
||||
<key name="CopyFile.RECENT_KEYS">
|
||||
<recent name="$PROJECT_DIR$" />
|
||||
</key>
|
||||
</component>
|
||||
<component name="SpellCheckerSettings" RuntimeDictionaries="0" Folders="0" CustomDictionaries="0" DefaultDictionary="application-level" UseSingleDictionary="true" transferred="true" />
|
||||
<component name="TaskManager">
|
||||
<task active="true" id="Default" summary="Default task">
|
||||
<changelist id="c0d2cb1a-45f7-4ae6-a3c7-4649a212b52b" name="Default Changelist" comment="" />
|
||||
<created>1604604985514</created>
|
||||
<option name="number" value="Default" />
|
||||
<option name="presentableId" value="Default" />
|
||||
<updated>1604604985514</updated>
|
||||
<workItem from="1604604986572" duration="1150000" />
|
||||
</task>
|
||||
<servers />
|
||||
</component>
|
||||
<component name="TypeScriptGeneratedFilesManager">
|
||||
<option name="version" value="3" />
|
||||
</component>
|
||||
</project>
|
11
babel.config.js
Normal file
11
babel.config.js
Normal file
@ -0,0 +1,11 @@
|
||||
module.exports = {
|
||||
presets: [
|
||||
[
|
||||
'@babel/preset-env', {
|
||||
targets: {
|
||||
esmodules: true
|
||||
}
|
||||
}
|
||||
]
|
||||
]
|
||||
}
|
21
lib/module.js
Normal file
21
lib/module.js
Normal file
@ -0,0 +1,21 @@
|
||||
const { resolve } = require('path')
|
||||
|
||||
module.exports = async function module(moduleOptions) {
|
||||
const defaultOptions = {
|
||||
id: 1,
|
||||
rpcUrl: '',
|
||||
rpcCallRetryAttempt: 15,
|
||||
blockGasLimit: 7300000
|
||||
}
|
||||
|
||||
const options = Object.assign({}, defaultOptions, this.options.provider, moduleOptions)
|
||||
|
||||
// Register plugin
|
||||
this.addPlugin({
|
||||
src: resolve(__dirname, 'plugin.js'),
|
||||
fileName: 'provider.js',
|
||||
options
|
||||
})
|
||||
}
|
||||
|
||||
module.exports.meta = require('../package.json')
|
301
lib/plugin.js
Normal file
301
lib/plugin.js
Normal file
@ -0,0 +1,301 @@
|
||||
const Web3 = require('web3')
|
||||
const { hexToNumberString, toChecksumAddress, numberToHex } = require('web3-utils')
|
||||
|
||||
export default (ctx, inject) => {
|
||||
const moduleOptions = <%= JSON.stringify(options) %>
|
||||
|
||||
const instance = class Provider {
|
||||
constructor(options) {
|
||||
this.address = ''
|
||||
this.version = 'new'
|
||||
|
||||
this.config = options.config
|
||||
this.web3 = new Web3(new Web3.providers.HttpProvider(options.rpcUrl))
|
||||
}
|
||||
|
||||
async initProvider(provider) {
|
||||
try {
|
||||
this.provider = provider
|
||||
this.web3 = new Web3(provider)
|
||||
|
||||
await this._checkVersion()
|
||||
return await this._initProvider()
|
||||
} catch (err) {
|
||||
throw new Error(`Provider method initProvider has error: ${err.message}`)
|
||||
}
|
||||
}
|
||||
|
||||
async sendRequest(params) {
|
||||
try {
|
||||
const request = args =>
|
||||
this.version === 'old' ? this._sendAsync(args) : this.provider.request(args)
|
||||
|
||||
return await request(params)
|
||||
} catch (err) {
|
||||
throw new Error(`Provider method sendRequest has error: ${err.message}`)
|
||||
}
|
||||
}
|
||||
|
||||
getContract({ abi, address }) {
|
||||
return new this.web3.eth.Contract(abi, address)
|
||||
}
|
||||
|
||||
async deployContract({ domain, deploymentActions, abi, address }) {
|
||||
try {
|
||||
const [{ bytecode, expectedAddress }] = deploymentActions.actions.filter(
|
||||
action => action.domain === domain
|
||||
)
|
||||
|
||||
const code = await this.web3.eth.getCode(expectedAddress)
|
||||
|
||||
if (code !== '0x') {
|
||||
throw new Error('Already deployed')
|
||||
}
|
||||
|
||||
const data = this.getContract({ abi, address })
|
||||
.methods.deploy(bytecode, deploymentActions.salt)
|
||||
.encodeABI()
|
||||
|
||||
const callParams = {
|
||||
method: 'eth_sendTransaction',
|
||||
params: [
|
||||
{
|
||||
from: this.address,
|
||||
to: this.getContract()._address,
|
||||
gas: numberToHex(6e6),
|
||||
gasPrice: '0x100000000',
|
||||
value: 0,
|
||||
data
|
||||
}
|
||||
],
|
||||
from: this.address
|
||||
}
|
||||
|
||||
return await this.sendRequest(callParams)
|
||||
} catch (err) {
|
||||
throw new Error(`Provider method deployContract has error: ${err.message}`)
|
||||
}
|
||||
}
|
||||
|
||||
async contractRequest({ methodName, data, to, from, gas, value = 0 }) {
|
||||
const { rpcCallRetryAttempt, blockGasLimit } = this.config
|
||||
|
||||
try {
|
||||
const params = {
|
||||
to,
|
||||
data,
|
||||
value,
|
||||
from: from || this.address,
|
||||
gas: gas || blockGasLimit + 100000
|
||||
}
|
||||
|
||||
return await this._repeatUntilResult(
|
||||
() => this.web3.eth[methodName](params),
|
||||
rpcCallRetryAttempt
|
||||
)
|
||||
} catch (err) {
|
||||
throw new Error(`Provider method contractRequest has error: ${err.message}`)
|
||||
}
|
||||
}
|
||||
|
||||
async getBalance({ address }) {
|
||||
const { rpcCallRetryAttempt } = this.config
|
||||
|
||||
try {
|
||||
const params = {
|
||||
method: 'eth_getBalance',
|
||||
params: [address, 'latest']
|
||||
}
|
||||
|
||||
const balance = await this._repeatUntilResult(
|
||||
() => this.sendRequest(params),
|
||||
rpcCallRetryAttempt
|
||||
)
|
||||
|
||||
return hexToNumberString(balance)
|
||||
} catch (err) {
|
||||
throw new Error(`Provider method getBalance has error: ${err.message}`)
|
||||
}
|
||||
}
|
||||
|
||||
async waitForTxReceipt({ txHash }) {
|
||||
const { rpcCallRetryAttempt } = this.config
|
||||
|
||||
try {
|
||||
const params = {
|
||||
method: 'eth_getTransactionReceipt',
|
||||
params: [txHash]
|
||||
}
|
||||
|
||||
return await this._repeatUntilResult(() => this.sendRequest(params), rpcCallRetryAttempt * 10)
|
||||
} catch (err) {
|
||||
throw new Error(`Provider method waitForTxReceipt has error: ${err.message}`)
|
||||
}
|
||||
}
|
||||
|
||||
async batchRequest({ txs, callback }) {
|
||||
try {
|
||||
const txsPromisesBucket = []
|
||||
|
||||
for (const [index, params] of txs.entries()) {
|
||||
const txPromise = this.sendRequest({
|
||||
method: 'eth_sendTransaction',
|
||||
params: [params]
|
||||
})
|
||||
|
||||
await this._sleep(1000)
|
||||
|
||||
if (!(index % 2) && index !== 0) {
|
||||
await txPromise
|
||||
}
|
||||
|
||||
txsPromisesBucket.push(txPromise)
|
||||
}
|
||||
|
||||
callback(txsPromisesBucket)
|
||||
|
||||
return await Promise.all(txsPromisesBucket)
|
||||
} catch (err) {
|
||||
throw new Error(err.message)
|
||||
}
|
||||
}
|
||||
|
||||
async checkNetworkVersion() {
|
||||
try {
|
||||
return await this.sendRequest({ method: 'net_version' })
|
||||
} catch (err) {
|
||||
throw new Error(`Provider method _checkNetworkVersion has error: ${err.message}`)
|
||||
}
|
||||
}
|
||||
|
||||
on({ method, callback }) {
|
||||
try {
|
||||
this.provider.on(method, callback)
|
||||
} catch (err) {
|
||||
throw new Error(`Provider method _checkNetworkVersion has error: ${err.message}`)
|
||||
}
|
||||
}
|
||||
|
||||
async _initProvider() {
|
||||
try {
|
||||
const request = () =>
|
||||
this.version ? this.provider.enable() : this.sendRequest({ method: 'eth_requestAccounts' })
|
||||
|
||||
const [account] = await request('')
|
||||
|
||||
if (!account) {
|
||||
throw new Error('Locked metamask')
|
||||
}
|
||||
|
||||
this.address = account
|
||||
|
||||
this.provider.on('accountsChanged', accounts => this._onAccountsChanged(accounts))
|
||||
this.provider.on('chainChanged', id => this._onNetworkChanged({ id }))
|
||||
|
||||
this.config.id = await this.checkNetworkVersion()
|
||||
|
||||
return toChecksumAddress(account)
|
||||
} catch (err) {
|
||||
throw new Error(`Provider method _initProvider has error: ${err.message}`)
|
||||
}
|
||||
}
|
||||
|
||||
_sleep(time) {
|
||||
return new Promise(resolve => {
|
||||
setTimeout(() => {
|
||||
resolve()
|
||||
}, time)
|
||||
})
|
||||
}
|
||||
|
||||
_sendAsync({ method, params, from }) {
|
||||
const { id } = this.config
|
||||
|
||||
switch (id) {
|
||||
case 77:
|
||||
case 99:
|
||||
case 100:
|
||||
from = undefined
|
||||
break
|
||||
}
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
const callback = (err, response) => {
|
||||
if (err || response.error) {
|
||||
reject(err)
|
||||
}
|
||||
|
||||
resolve(response.result)
|
||||
}
|
||||
|
||||
this.provider.sendAsync(
|
||||
{
|
||||
method,
|
||||
params,
|
||||
jsonrpc: '2.0',
|
||||
from
|
||||
},
|
||||
callback
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
async _send({ method, params }) {
|
||||
try {
|
||||
return await this.provider.send(method, params)
|
||||
} catch (err) {
|
||||
throw new Error(`Provider method _send has error: ${err.message}`)
|
||||
}
|
||||
}
|
||||
|
||||
_onNetworkChanged({ id }) {
|
||||
if (id) {
|
||||
this.network = id
|
||||
window.location.reload()
|
||||
}
|
||||
}
|
||||
|
||||
_onAccountsChanged(accounts) {
|
||||
const [account] = accounts
|
||||
|
||||
if (account) {
|
||||
this.address = toChecksumAddress(account)
|
||||
window.location.reload()
|
||||
}
|
||||
}
|
||||
|
||||
_checkVersion() {
|
||||
if (this.provider && this.provider.request) {
|
||||
this.version = 'new'
|
||||
} else {
|
||||
this.version = 'old'
|
||||
}
|
||||
}
|
||||
|
||||
_repeatUntilResult(action, totalAttempts, retryAttempt = 1) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const iteration = async () => {
|
||||
const result = await action()
|
||||
|
||||
if (!result) {
|
||||
if (retryAttempt <= totalAttempts) {
|
||||
retryAttempt++
|
||||
setTimeout(iteration, 1000 * retryAttempt)
|
||||
} else {
|
||||
return reject(new Error('Tx not minted'))
|
||||
}
|
||||
} else {
|
||||
resolve(result)
|
||||
}
|
||||
}
|
||||
|
||||
iteration()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const provider = new instance({ config: moduleOptions })
|
||||
|
||||
inject('provider', provider)
|
||||
ctx.$provider = provider
|
||||
}
|
5
nuxt.config.js
Normal file
5
nuxt.config.js
Normal file
@ -0,0 +1,5 @@
|
||||
export default {
|
||||
modules: [
|
||||
['@nuxtjs/provider']
|
||||
],
|
||||
}
|
32
package.json
Normal file
32
package.json
Normal file
@ -0,0 +1,32 @@
|
||||
{
|
||||
"name": "@nuxtjs/provider",
|
||||
"version": "0.0.1",
|
||||
"description": "Provider integration with Nuxt.js",
|
||||
"repository": "provider-module",
|
||||
"license": "MIT",
|
||||
"contributors": "nikdementev",
|
||||
"main": "lib/module.js",
|
||||
"types": "types/index.d.ts",
|
||||
"files": [
|
||||
"lib",
|
||||
"types/*.d.ts"
|
||||
],
|
||||
"scripts": {
|
||||
"lint": "eslint lib test",
|
||||
"release": "standard-version && git push --follow-tags && npm publish"
|
||||
},
|
||||
"dependencies": {
|
||||
"web3": "^1.3.0",
|
||||
"web3-utils": "^1.3.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "latest",
|
||||
"@babel/preset-env": "latest",
|
||||
"@nuxtjs/eslint-config": "latest",
|
||||
"babel-eslint": "latest",
|
||||
"babel-jest": "latest",
|
||||
"eslint": "latest",
|
||||
"nuxt-edge": "latest",
|
||||
"standard-version": "latest"
|
||||
}
|
||||
}
|
94
types/index.d.ts
vendored
Normal file
94
types/index.d.ts
vendored
Normal file
@ -0,0 +1,94 @@
|
||||
import Vue from 'vue'
|
||||
import Web3 from 'web3'
|
||||
|
||||
import './vuex'
|
||||
|
||||
type Address = string
|
||||
|
||||
type Params = {
|
||||
to: string
|
||||
gas: string
|
||||
from: string
|
||||
data: string
|
||||
value: string
|
||||
gasPrice: string
|
||||
}
|
||||
|
||||
type RequestParams = {
|
||||
method: string
|
||||
params?: Params[] | object;
|
||||
}
|
||||
|
||||
type ContractRequestParams = {
|
||||
to: string
|
||||
gas: string
|
||||
from: string
|
||||
methodName: string
|
||||
data?: string
|
||||
value?: number
|
||||
}
|
||||
|
||||
export type TransactionStatus =
|
||||
| 'success'
|
||||
| 'fail'
|
||||
| 'pending'
|
||||
|
||||
export interface TransactionReceipt {
|
||||
transactionResult: unknown
|
||||
status: TransactionStatus
|
||||
transactionError?: string
|
||||
}
|
||||
|
||||
type GetBalanceParams = {
|
||||
address: string
|
||||
}
|
||||
|
||||
type WaitForTxReceiptParams = {
|
||||
address: string
|
||||
}
|
||||
|
||||
type BatchRequestParams = {
|
||||
txs: Params[]
|
||||
callback?: (params: Promise<string>[]) => void
|
||||
}
|
||||
|
||||
type OnListenerParams = {
|
||||
method: string
|
||||
callback: CallableFunction
|
||||
}
|
||||
|
||||
interface ProviderOptions {
|
||||
id?: string,
|
||||
rpcUrl?: string,
|
||||
rpcCallRetryAttempt?: number,
|
||||
blockGasLimit?: number,
|
||||
}
|
||||
|
||||
interface ProviderInstance {
|
||||
readonly web3: typeof Web3
|
||||
readonly config: ProviderOptions
|
||||
|
||||
initProvider(provider: unknown): Promise<Address>
|
||||
sendRequest(params: RequestParams): Promise<TransactionReceipt>
|
||||
contractRequest(params: ContractRequestParams): Promise<TransactionReceipt>
|
||||
getBalance(params: GetBalanceParams): Promise<number>
|
||||
waitForTxReceipt(params: WaitForTxReceiptParams): Promise<TransactionReceipt>
|
||||
batchRequest(params: WaitForTxReceiptParams): Promise<string[]>
|
||||
checkNetworkVersion(params: WaitForTxReceiptParams): Promise<string>
|
||||
on(params: OnListenerParams): void
|
||||
}
|
||||
|
||||
declare module '@nuxt/vue-app' {
|
||||
interface Context {
|
||||
$axios: ProviderInstance
|
||||
}
|
||||
interface NuxtAppOptions {
|
||||
$axios: ProviderInstance
|
||||
}
|
||||
}
|
||||
|
||||
declare module 'vue/types/vue' {
|
||||
interface Vue {
|
||||
$provider: ProviderInstance
|
||||
}
|
||||
}
|
7
types/vue.d.ts
vendored
Normal file
7
types/vue.d.ts
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
import { ProviderInstance } from '.'
|
||||
|
||||
declare module 'vuex/types/index' {
|
||||
interface Store<S> {
|
||||
$provider: ProviderInstance,
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user