Skip to content

Commit

Permalink
[web-wallet] Add scripts to pages for dapps
Browse files Browse the repository at this point in the history
  • Loading branch information
kent-white authored and aptos-bot committed May 3, 2022
1 parent a1b0ea0 commit 7984743
Show file tree
Hide file tree
Showing 13 changed files with 1,771 additions and 1,320 deletions.
4 changes: 3 additions & 1 deletion ecosystem/web-wallet/.eslintrc.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
module.exports = {
env: {
browser: true,
es2021: true
es2021: true,
jest: true,
webextensions: true
},
extends: [
'plugin:react/recommended',
Expand Down
15 changes: 12 additions & 3 deletions ecosystem/web-wallet/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,14 @@
"react-icons": "^4.3.1",
"react-router-dom": "^6.3.0",
"react-scripts": "5.0.1",
"typescript": "^4.6.3"
"webextension-polyfill": "^0.9.0"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"prebuild": "rimraf build",
"build": "npm-run-all build:*",
"build:app": "INLINE_RUNTIME_CHUNK=false react-scripts build",
"build:bg": "webpack --mode production ./src/background.ts --output-path ./build --output-filename background.ts",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
Expand All @@ -50,14 +53,20 @@
]
},
"devDependencies": {
"@types/chrome": "^0.0.183",
"@types/react": "^18.0.6",
"@types/webextension-polyfill": "^0.8.3",
"@typescript-eslint/eslint-plugin": "^5.20.0",
"@typescript-eslint/parser": "^5.20.0",
"eslint": "^8.13.0",
"eslint-config-standard": "^17.0.0",
"eslint-plugin-import": "^2.26.0",
"eslint-plugin-n": "^15.1.0",
"eslint-plugin-promise": "^6.0.0",
"eslint-plugin-react": "^7.29.4"
"eslint-plugin-react": "^7.29.4",
"npm-run-all": "^4.1.5",
"ts-loader": "^9.3.0",
"typescript": "^4.6.3",
"webpack-cli": "^4.9.2"
}
}
16 changes: 16 additions & 0 deletions ecosystem/web-wallet/public/contentscript.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// Copyright (c) Aptos
// SPDX-License-Identifier: Apache-2.0

function injectScript () {
try {
const container = document.head || document.documentElement
const scriptTag = document.createElement('script')
scriptTag.src = chrome.runtime.getURL('inpage.js')
container.insertBefore(scriptTag, container.children[0])
container.removeChild(scriptTag)
} catch (error) {
console.error('Aptos injection failed.', error)
}
}

injectScript()
34 changes: 34 additions & 0 deletions ecosystem/web-wallet/public/inpage.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// Copyright (c) Aptos
// SPDX-License-Identifier: Apache-2.0

const extensionId = 'jmmhmakollmjgkjgnbeppkccgddmjnib'

class Web3 {
account () {
return new Promise(function (resolve, reject) {
chrome.runtime.sendMessage(extensionId, { method: 'getAccountAddress' }, function (response) {
if (response.address) {
resolve(response.address)
} else {
reject(response.error ?? 'Error')
}
return true
})
})
}

signTransaction (transaction, completion) {
return new Promise(function (resolve, reject) {
chrome.runtime.sendMessage(extensionId, { method: 'signTransaction', transaction }, function (response) {
if (response.transaction) {
resolve(response.transaction)
} else {
reject(response.error ?? 'Error')
}
return true
})
})
}
}

window.aptos = new Web3()
17 changes: 17 additions & 0 deletions ecosystem/web-wallet/public/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,22 @@
"manifest_version": 2,
"browser_action": {
"default_popup": "index.html"
},
"content_scripts": [{
"matches": ["<all_urls>"],
"js": [
"contentscript.ts"
]
}],
"web_accessible_resources": [
"inpage.js"
],
"background": {
"scripts": ["background.ts"],
"persistent": true
},
"externally_connectable": {
"matches": ["http://localhost/*"],
"ids": ["*"]
}
}
45 changes: 45 additions & 0 deletions ecosystem/web-wallet/src/background.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// Copyright (c) Aptos
// SPDX-License-Identifier: Apache-2.0

import { AptosAccount, AptosClient, Types } from 'aptos'
import { devnetNodeUrl } from './constants'
import { MessageMethod } from './types'
import { getAptosAccountState } from './utils/account'

chrome.runtime.onMessageExternal.addListener(async function (request, _sender, sendResponse) {
const account = getAptosAccountState()
if (account === undefined) {
sendResponse({ error: 'No Accounts' })
return
}
switch (request.method) {
case MessageMethod.GET_ACCOUNT_ADDRESS:
getAccountAddress(account, sendResponse)
break;
case MessageMethod.SIGN_TRANSACTION:
signTransaction(account, request.transaction, sendResponse)
break;
default:
throw(request.method + ' method is not supported')
}
})

function getAccountAddress( account: AptosAccount, sendResponse: (response?: any) => void) {
if (account.address()) {
sendResponse({ address: account.address().hex() })
} else {
sendResponse({ error: 'No accounts signed in' })
}
}

async function signTransaction (account: AptosAccount, transaction: Types.UserTransactionRequest, sendResponse: (response?: any) => void) {
const client = new AptosClient(devnetNodeUrl)
const message = await client.createSigningMessage(transaction)
const signatureHex = account.signHexString(message.substring(2))
const transactionSignature = {
type: 'ed25519_signature',
public_key: account.pubKey().hex(),
signature: signatureHex.hex()
}
sendResponse({ transaction: { signature: transactionSignature, ...transaction } })
}
1 change: 1 addition & 0 deletions ecosystem/web-wallet/src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
export const KEY_LENGTH: number = 64
export const DEVNET_NODE_URL = 'https://fullnode.devnet.aptoslabs.com'
export const FAUCET_URL = 'https://faucet.devnet.aptoslabs.com'
export const walletStateLocalStorageKey = 'aptosWalletState'

export const secondaryBgColor = {
dark: 'gray.900',
Expand Down
39 changes: 7 additions & 32 deletions ecosystem/web-wallet/src/hooks/useWalletState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,50 +3,25 @@

import { useState, useCallback } from 'react'
import constate from 'constate'
import { AptosAccount, AptosAccountObject } from 'aptos'
import { getAptosAccountState, getLocalStorageState } from '../utils/account'
import { walletStateLocalStorageKey } from '../constants'
import { AptosAccountState, LocalStorageState } from '../types'

export type AptosAccountState = AptosAccount | undefined;

export interface LocalStorageState {
aptosAccountObject?: AptosAccountObject,
const defaultValue: LocalStorageState = {
aptosAccountObject: undefined
}

export interface UpdateWalletStateProps {
aptosAccountState: AptosAccountState
}

const defaultValue: LocalStorageState = {
aptosAccountObject: undefined
}

const walletStateLocalStorageKey = 'aptosWalletState'

export default function useWalletState () {
const [localStorageState, setLocalStorageState] = useState<LocalStorageState>(() => {
try {
// Get from local storage by key
const item = window.localStorage.getItem(walletStateLocalStorageKey)
const result: LocalStorageState = item ? JSON.parse(item) : defaultValue
return result
} catch (error) {
return defaultValue
}
return getLocalStorageState() ?? defaultValue
})

const [aptosAccount, setAptosAccount] = useState<AptosAccountState>(() => {
try {
const item = window.localStorage.getItem(walletStateLocalStorageKey)
const localStorageState: AptosAccountObject = item ? JSON.parse(item) : defaultValue
if (localStorageState) {
const aptosAccount = AptosAccount.fromAptosAccountObject(localStorageState)
return aptosAccount
} else {
console.log('Unable to retrieve from local storage')
return undefined
}
} catch (err) {
return undefined
}
return getAptosAccountState()
})

const updateWalletState = useCallback(({ aptosAccountState }: UpdateWalletStateProps) => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,19 @@
// Copyright (c) Aptos
// SPDX-License-Identifier: Apache-2.0

import { AptosAccount, AptosAccountObject } from 'aptos'

export type AptosAccountState = AptosAccount | undefined;

export interface LocalStorageState {
aptosAccountObject?: AptosAccountObject,
}

export const MessageMethod = Object.freeze({
GET_ACCOUNT_ADDRESS: 'getAccountAddress',
SIGN_TRANSACTION: 'signTransaction'
} as const)

export class Ok<T, E> {
public constructor (public readonly value: T) {
this.value = value
Expand Down
27 changes: 24 additions & 3 deletions ecosystem/web-wallet/src/utils/account.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
// Copyright (c) Aptos
// SPDX-License-Identifier: Apache-2.0

import { AptosAccount } from 'aptos'
import { AptosAccount, AptosAccountObject } from 'aptos'
import { Buffer } from 'buffer'
import { KEY_LENGTH } from '../constants'
import { Result, err, ok } from '../types'
import { KEY_LENGTH, walletStateLocalStorageKey } from '../constants'
import { AptosAccountState, LocalStorageState, Result, err, ok } from '../types'

export function loginAccount (key: string): Result<AptosAccount, Error> {
if (key.length === KEY_LENGTH) {
Expand All @@ -26,3 +26,24 @@ export function createNewAccount (): AptosAccount {
// todo: make request to create account on chain
return account
}

export function getLocalStorageState (): LocalStorageState | null {
// Get from local storage by key
const item = window.localStorage.getItem(walletStateLocalStorageKey)
if (item) {
const accountObject: AptosAccountObject = JSON.parse(item)
return { aptosAccountObject: accountObject }
} else {
return null
}
}

export function getAptosAccountState (): AptosAccountState {
const localStorage = getLocalStorageState()
if (localStorage) {
const { aptosAccountObject } = localStorage
return aptosAccountObject ? AptosAccount.fromAptosAccountObject(aptosAccountObject) : undefined
} else {
return undefined
}
}
4 changes: 2 additions & 2 deletions ecosystem/web-wallet/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@
"allowSyntheticDefaultImports": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"module": "esnext",
"module": "commonjs",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"noEmit": false,
"jsx": "react"
},
"include": [
Expand Down
10 changes: 10 additions & 0 deletions ecosystem/web-wallet/webpack.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
module.exports = {
resolve: {
extensions: ['.ts', '.tsx', '.js', '.json']
},
module: {
rules: [
{ test: /\.tsx?$/, loader: "ts-loader" }
]
}
};
Loading

0 comments on commit 7984743

Please sign in to comment.