mirror of
https://github.com/Instadapp/vue-web3.git
synced 2024-07-29 21:48:25 +00:00
Initial commit
This commit is contained in:
commit
400a2d7581
7
.gitignore
vendored
Normal file
7
.gitignore
vendored
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
# Library
|
||||||
|
node_modules
|
||||||
|
yarn-error.log
|
||||||
|
dist
|
||||||
|
.vscode
|
||||||
|
# OS
|
||||||
|
.DS_Store
|
6
.prettierrc
Normal file
6
.prettierrc
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
{
|
||||||
|
"singleQuote": true,
|
||||||
|
"trailingComma": "all",
|
||||||
|
"semi": false,
|
||||||
|
"arrowParens": "always"
|
||||||
|
}
|
5
build.config.ts
Normal file
5
build.config.ts
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
import { defineBuildConfig } from 'unbuild'
|
||||||
|
|
||||||
|
export default defineBuildConfig({
|
||||||
|
entries: ['./src/index'],
|
||||||
|
})
|
10
jest.config.js
Normal file
10
jest.config.js
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
module.exports = {
|
||||||
|
preset: 'ts-jest',
|
||||||
|
globals: {
|
||||||
|
'ts-jest': {
|
||||||
|
diagnostics: {
|
||||||
|
warnOnly: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
63
package.json
Normal file
63
package.json
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
{
|
||||||
|
"name": "@kabbouchi/vue-web3",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"description": "Vue web3 composition api",
|
||||||
|
"license": "MIT",
|
||||||
|
"main": "dist/index.js",
|
||||||
|
"module": "dist/index.mjs",
|
||||||
|
"types": "dist/src/index.d.ts",
|
||||||
|
"scripts": {
|
||||||
|
"dev": "jiti scripts/watch.ts --cache",
|
||||||
|
"build": "unbuild",
|
||||||
|
"lint": "prettier -c --parser typescript \"{src,tests}/**/*.[jt]s?(x)\"",
|
||||||
|
"lint:fix": "yarn run lint --write",
|
||||||
|
"test:types": "tsc --build tsconfig.json",
|
||||||
|
"test:unit": "jest",
|
||||||
|
"test": "yarn run test:types && yarn run test:unit"
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"dist/**/*",
|
||||||
|
"LICENSE",
|
||||||
|
"README.md"
|
||||||
|
],
|
||||||
|
"dependencies": {
|
||||||
|
"@ethersproject/bytes": "^5.4.0",
|
||||||
|
"@ethersproject/keccak256": "^5.4.0",
|
||||||
|
"@web3-react/abstract-connector": "^6.0.7",
|
||||||
|
"@web3-react/types": "^6.0.7",
|
||||||
|
"tiny-invariant": "^1.1.0",
|
||||||
|
"vue-demi": "^0.11.3"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/jest": "^27.0.1",
|
||||||
|
"chokidar": "^3.5.2",
|
||||||
|
"jest": "^27.0.6",
|
||||||
|
"lint-staged": "^11.1.2",
|
||||||
|
"pascalcase": "^1.0.0",
|
||||||
|
"prettier": "^2.3.2",
|
||||||
|
"ts-jest": "^27.0.5",
|
||||||
|
"typescript": "^4.3.5",
|
||||||
|
"unbuild": "^0.4.2",
|
||||||
|
"vue": "^3.2.6"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@vue/composition-api": "^1.0.0-rc.1",
|
||||||
|
"vue": "^2.0.0 || >=3.0.0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@vue/composition-api": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"gitHooks": {
|
||||||
|
"pre-commit": "lint-staged"
|
||||||
|
},
|
||||||
|
"lint-staged": {
|
||||||
|
"*.js": [
|
||||||
|
"prettier --write"
|
||||||
|
],
|
||||||
|
"*.ts?(x)": [
|
||||||
|
"prettier --parser=typescript --write"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
6
renovate.json
Normal file
6
renovate.json
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
{
|
||||||
|
"extends": ["@nuxtjs"],
|
||||||
|
"lockFileMaintenance": {
|
||||||
|
"enabled": true
|
||||||
|
}
|
||||||
|
}
|
32
scripts/release.sh
Executable file
32
scripts/release.sh
Executable file
|
@ -0,0 +1,32 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Restore all git changes
|
||||||
|
git restore -s@ -SW -- example src test
|
||||||
|
|
||||||
|
# Resolve yarn
|
||||||
|
yarn
|
||||||
|
|
||||||
|
# Update token
|
||||||
|
if [[ ! -z ${NODE_AUTH_TOKEN} ]] ; then
|
||||||
|
echo "//registry.npmjs.org/:_authToken=${NODE_AUTH_TOKEN}" >> ~/.npmrc
|
||||||
|
echo "registry=https://registry.npmjs.org/" >> ~/.npmrc
|
||||||
|
echo "always-auth=true" >> ~/.npmrc
|
||||||
|
npm whoami
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Get package name from package.json
|
||||||
|
PACKAGE_NAME=$(
|
||||||
|
cat package.json \
|
||||||
|
| grep name \
|
||||||
|
| head -1 \
|
||||||
|
| awk -F: '{ print $2 }' \
|
||||||
|
| sed 's/[",]//g'
|
||||||
|
)
|
||||||
|
|
||||||
|
# Release package
|
||||||
|
echo "🚀 Publishing$PACKAGE_NAME"
|
||||||
|
if npm publish -q --access public ; then
|
||||||
|
echo "✅ Published$PACKAGE_NAME"
|
||||||
|
else
|
||||||
|
echo "❌ Could'nt publish$PACKAGE_NAME"
|
||||||
|
fi
|
25
scripts/watch.ts
Normal file
25
scripts/watch.ts
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
import { watch } from 'chokidar'
|
||||||
|
import { build } from 'unbuild'
|
||||||
|
import { resolve } from 'upath'
|
||||||
|
import consola from 'consola'
|
||||||
|
|
||||||
|
// Package root
|
||||||
|
const rootDir = resolve(__dirname, '..')
|
||||||
|
// Package src
|
||||||
|
const src = resolve(__dirname, '../src')
|
||||||
|
|
||||||
|
// Package build promise
|
||||||
|
const tryBuild = async () => {
|
||||||
|
try {
|
||||||
|
await build(rootDir, false)
|
||||||
|
} catch (e) {
|
||||||
|
consola.log(e)
|
||||||
|
} finally {
|
||||||
|
consola.info('Waiting for changes...')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Watch src, rebuild on any change
|
||||||
|
watch(src).on('change', tryBuild)
|
||||||
|
watch(src).on('add', tryBuild)
|
||||||
|
watch(src).on('unlink', tryBuild)
|
125
src/index.ts
Normal file
125
src/index.ts
Normal file
|
@ -0,0 +1,125 @@
|
||||||
|
import { AbstractConnector } from '@web3-react/abstract-connector'
|
||||||
|
import { normalizeAccount, normalizeChainId } from './normalizers'
|
||||||
|
import { ConnectorUpdate } from '@web3-react/types'
|
||||||
|
import { computed, ref, watch } from 'vue-demi'
|
||||||
|
|
||||||
|
class UnsupportedChainIdError extends Error {
|
||||||
|
public constructor(
|
||||||
|
unsupportedChainId: number,
|
||||||
|
supportedChainIds?: readonly number[],
|
||||||
|
) {
|
||||||
|
super()
|
||||||
|
this.name = this.constructor.name
|
||||||
|
this.message = `Unsupported chain id: ${unsupportedChainId}. Supported chain ids are: ${supportedChainIds}.`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const connector = ref<AbstractConnector>()
|
||||||
|
const chainId = ref()
|
||||||
|
const account = ref<null | string>()
|
||||||
|
const provider = ref<any>()
|
||||||
|
const error = ref<Error>()
|
||||||
|
const active = computed(
|
||||||
|
() =>
|
||||||
|
connector.value !== undefined &&
|
||||||
|
chainId.value !== undefined &&
|
||||||
|
account.value !== undefined &&
|
||||||
|
!!!error.value,
|
||||||
|
)
|
||||||
|
const library = ref()
|
||||||
|
|
||||||
|
let getLibrary = (provider?: any, connector?: any) => () => null
|
||||||
|
|
||||||
|
export const setWeb3LibraryCallback = (
|
||||||
|
cb: (provider?: any, connector?: any) => any,
|
||||||
|
) => {
|
||||||
|
getLibrary = cb
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useWeb3 = () => {
|
||||||
|
const activate = async (
|
||||||
|
c: AbstractConnector,
|
||||||
|
onError?: (error: Error) => void,
|
||||||
|
throwErrors: boolean = false,
|
||||||
|
) => {
|
||||||
|
let activated = false
|
||||||
|
|
||||||
|
try {
|
||||||
|
const update = await c.activate().then((update) => {
|
||||||
|
activated = true
|
||||||
|
return update
|
||||||
|
})
|
||||||
|
|
||||||
|
const augmentedUpdate = await augmentConnectorUpdate(c, update)
|
||||||
|
|
||||||
|
connector.value = c
|
||||||
|
chainId.value = augmentedUpdate.chainId
|
||||||
|
provider.value = augmentedUpdate.provider
|
||||||
|
account.value = augmentedUpdate.account
|
||||||
|
} catch (e) {
|
||||||
|
error.value = e
|
||||||
|
|
||||||
|
if (throwErrors) {
|
||||||
|
activated && c.deactivate()
|
||||||
|
throw e
|
||||||
|
} else if (onError) {
|
||||||
|
activated && c.deactivate()
|
||||||
|
onError(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const deactivate = () => {
|
||||||
|
connector.value?.deactivate()
|
||||||
|
}
|
||||||
|
|
||||||
|
watch([active, provider, connector, chainId], () => {
|
||||||
|
library.value =
|
||||||
|
active.value &&
|
||||||
|
chainId.value !== undefined &&
|
||||||
|
Number.isInteger(chainId.value) &&
|
||||||
|
!!connector.value
|
||||||
|
? getLibrary(provider.value, connector.value)
|
||||||
|
: undefined
|
||||||
|
})
|
||||||
|
|
||||||
|
return {
|
||||||
|
library,
|
||||||
|
active,
|
||||||
|
activate,
|
||||||
|
deactivate,
|
||||||
|
connector,
|
||||||
|
chainId,
|
||||||
|
account,
|
||||||
|
provider,
|
||||||
|
error,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function augmentConnectorUpdate(
|
||||||
|
connector: AbstractConnector,
|
||||||
|
update: ConnectorUpdate,
|
||||||
|
): Promise<ConnectorUpdate<number>> {
|
||||||
|
const provider =
|
||||||
|
update.provider === undefined
|
||||||
|
? await connector.getProvider()
|
||||||
|
: update.provider
|
||||||
|
const [_chainId, _account] = (await Promise.all([
|
||||||
|
update.chainId === undefined ? connector.getChainId() : update.chainId,
|
||||||
|
update.account === undefined ? connector.getAccount() : update.account,
|
||||||
|
])) as [
|
||||||
|
Required<ConnectorUpdate>['chainId'],
|
||||||
|
Required<ConnectorUpdate>['account'],
|
||||||
|
]
|
||||||
|
|
||||||
|
const chainId = normalizeChainId(_chainId)
|
||||||
|
if (
|
||||||
|
!!connector.supportedChainIds &&
|
||||||
|
!connector.supportedChainIds.includes(chainId)
|
||||||
|
) {
|
||||||
|
throw new UnsupportedChainIdError(chainId, connector.supportedChainIds)
|
||||||
|
}
|
||||||
|
const account = _account === null ? _account : normalizeAccount(_account)
|
||||||
|
|
||||||
|
return { provider, chainId, account }
|
||||||
|
}
|
63
src/normalizers.ts
Normal file
63
src/normalizers.ts
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
import { arrayify } from '@ethersproject/bytes'
|
||||||
|
import { keccak256 } from '@ethersproject/keccak256'
|
||||||
|
import invariant from 'tiny-invariant'
|
||||||
|
|
||||||
|
export function normalizeChainId(chainId: string | number): number {
|
||||||
|
if (typeof chainId === 'string') {
|
||||||
|
// Temporary fix until the next version of Metamask Mobile gets released.
|
||||||
|
// In the current version (0.2.13), the chainId starts with “Ox” rather
|
||||||
|
// than “0x”. Fix: https://github.com/MetaMask/metamask-mobile/pull/1275
|
||||||
|
chainId = chainId.replace(/^Ox/, '0x')
|
||||||
|
|
||||||
|
const parsedChainId = Number.parseInt(
|
||||||
|
chainId,
|
||||||
|
chainId.trim().substring(0, 2) === '0x' ? 16 : 10,
|
||||||
|
)
|
||||||
|
invariant(
|
||||||
|
!Number.isNaN(parsedChainId),
|
||||||
|
`chainId ${chainId} is not an integer`,
|
||||||
|
)
|
||||||
|
return parsedChainId
|
||||||
|
} else {
|
||||||
|
invariant(Number.isInteger(chainId), `chainId ${chainId} is not an integer`)
|
||||||
|
return chainId
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://github.com/ethers-io/ethers.js/blob/d9d438a119bb11f8516fc9cf02c534ab3816fcb3/packages/address/src.ts/index.ts
|
||||||
|
export function normalizeAccount(_address: string): string {
|
||||||
|
invariant(
|
||||||
|
typeof _address === 'string' && _address.match(/^(0x)?[0-9a-fA-F]{40}$/),
|
||||||
|
`Invalid address ${_address}`,
|
||||||
|
)
|
||||||
|
|
||||||
|
const address = _address.substring(0, 2) === '0x' ? _address : `0x${_address}`
|
||||||
|
const chars = address.toLowerCase().substring(2).split('')
|
||||||
|
|
||||||
|
const charsArray = new Uint8Array(40)
|
||||||
|
for (let i = 0; i < 40; i++) {
|
||||||
|
charsArray[i] = chars[i].charCodeAt(0)
|
||||||
|
}
|
||||||
|
const hashed = arrayify(keccak256(charsArray))
|
||||||
|
|
||||||
|
for (let i = 0; i < 40; i += 2) {
|
||||||
|
if (hashed[i >> 1] >> 4 >= 8) {
|
||||||
|
chars[i] = chars[i].toUpperCase()
|
||||||
|
}
|
||||||
|
if ((hashed[i >> 1] & 0x0f) >= 8) {
|
||||||
|
chars[i + 1] = chars[i + 1].toUpperCase()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const addressChecksum = `0x${chars.join('')}`
|
||||||
|
|
||||||
|
invariant(
|
||||||
|
!(
|
||||||
|
address.match(/([A-F].*[a-f])|([a-f].*[A-F])/) &&
|
||||||
|
address !== addressChecksum
|
||||||
|
),
|
||||||
|
`Bad address checksum ${address} ${addressChecksum}`,
|
||||||
|
)
|
||||||
|
|
||||||
|
return addressChecksum
|
||||||
|
}
|
3
tests/index.spec.ts
Normal file
3
tests/index.spec.ts
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
describe('useWeb3', () => {
|
||||||
|
it('returns default value', () => {})
|
||||||
|
})
|
31
tsconfig.json
Normal file
31
tsconfig.json
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
{
|
||||||
|
"include": ["scripts/watch.ts", "src/**/*", "tests/**/*"],
|
||||||
|
"exclude": ["dist", "node_modules"],
|
||||||
|
"compilerOptions": {
|
||||||
|
"rootDir": ".",
|
||||||
|
"outDir": "dist",
|
||||||
|
"sourceMap": false,
|
||||||
|
"noEmit": true,
|
||||||
|
|
||||||
|
"target": "esnext",
|
||||||
|
"module": "esnext",
|
||||||
|
"moduleResolution": "node",
|
||||||
|
"skipLibCheck": true,
|
||||||
|
|
||||||
|
"noUnusedLocals": true,
|
||||||
|
"strictNullChecks": true,
|
||||||
|
"noImplicitAny": true,
|
||||||
|
"noImplicitThis": true,
|
||||||
|
"noImplicitReturns": true,
|
||||||
|
"strict": true,
|
||||||
|
"isolatedModules": false,
|
||||||
|
|
||||||
|
"experimentalDecorators": true,
|
||||||
|
"resolveJsonModule": true,
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"removeComments": false,
|
||||||
|
|
||||||
|
"lib": ["esnext"],
|
||||||
|
"types": ["node", "jest"]
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user