Skip to content

Commit

Permalink
Merge pull request #1 from XPRNetwork/plugin-initial
Browse files Browse the repository at this point in the history
Plugin initial implementation
  • Loading branch information
metallicusdev authored Jan 15, 2024
2 parents 710fbe9 + c6d39da commit 352829b
Show file tree
Hide file tree
Showing 30 changed files with 3,951 additions and 671 deletions.
63 changes: 53 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,20 +1,63 @@
# @wharfkit/wallet-plugin-template
# @proton/wallet-plugin-webauth

A template to create a `WalletPlugin` for use within the `@wharfkit/session` library.
A Session Kit wallet plugin for the [WebAuth](https://xprnetwork.org/wallet) wallet.

## Usage

- [Use this as a template.](https://docs.github.com/en/repositories/creating-and-managing-repositories/creating-a-repository-from-a-template)
- Write your wallet plugin's logic.
- Publish it on Github or npmjs.com
- Include it in your project and use it.
Include this wallet plugin while initializing the SessionKit.

Mobile device and browser authentications are supported

**NOTE**: This wallet plugin will only work with the SessionKit and requires a browser-based environment.

```ts
import {WalletPluginWebAuth} from '@proton/wallet-plugin-webauth'

const kit = new SessionKit({
// ... your other options
walletPlugins: [new WalletPluginWebAuth()],
})
```

Main and test networks are supported

```ts

import {WalletPluginWebAuth} from '@proton/wallet-plugin-webauth'

const kit = new SessionKit({
// ... your other options
walletPlugins: [
new WalletPluginWebAuth({
scheme: 'proton-dev' // 'esr' | 'proton' | 'proton-dev'
}),
],
})
```

Custom buoy url and websocket class are supported.

```ts
import WebSocket from 'isomorphic-ws'
import {WalletPluginWebAuth} from '@proton/wallet-plugin-webauth'

const kit = new SessionKit({
// ... your other options
walletPlugins: [
new WalletPluginWebAuth({
buoyUrl: 'https://cb.anchor.link',
buoyWs: Websocket,
}),
],
})
```

## Example

You can find working example in `examples` folder

## Developing

You need [Make](https://www.gnu.org/software/make/), [node.js](https://nodejs.org/en/) and [yarn](https://classic.yarnpkg.com/en/docs/install) installed.

Clone the repository and run `make` to checkout all dependencies and build the project. See the [Makefile](./Makefile) for other useful targets. Before submitting a pull request make sure to run `make lint`.

---

Made with ☕️ & ❤️ by [Greymass](https://greymass.com), if you find this useful please consider [supporting us](https://greymass.com/support-us).
18 changes: 18 additions & 0 deletions examples/.eslintrc.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
module.exports = {
root: true,
env: { browser: true, es2020: true },
extends: [
'eslint:recommended',
'plugin:@typescript-eslint/recommended',
'plugin:react-hooks/recommended',
],
ignorePatterns: ['dist', '.eslintrc.cjs'],
parser: '@typescript-eslint/parser',
plugins: ['react-refresh'],
rules: {
'react-refresh/only-export-components': [
'warn',
{ allowConstantExport: true },
],
},
}
24 changes: 24 additions & 0 deletions examples/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*

node_modules
dist
dist-ssr
*.local

# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
12 changes: 12 additions & 0 deletions examples/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Example of @proton/wallet-plugin-webauth usage

## Project setup
```
yarn
```
**NOTE**: This example uses prebuild library from parent folder. So need to run `make` command there before running this example.

### Project start
```
yarn dev
```
17 changes: 17 additions & 0 deletions examples/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<!doctype html>
<html lang="en">

<head>
<meta charset="UTF-8" />
<meta name="viewport"
content="width=device-width, initial-scale=1.0" />
<title>WebAuth Wharfkit plugin example</title>
</head>

<body>
<div id="root"></div>
<script type="module"
src="/src/main.tsx"></script>
</body>

</html>
33 changes: 33 additions & 0 deletions examples/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
{
"name": "react-example",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "tsc && vite build",
"lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
"preview": "vite preview"
},
"dependencies": {
"@wharfkit/session": "^1.1.1",
"@wharfkit/web-renderer": "^1.1.1",
"react": "^18.2.0",
"react-dom": "^18.2.0"
},
"devDependencies": {
"@types/react": "^18.2.15",
"@types/react-dom": "^18.2.7",
"@typescript-eslint/eslint-plugin": "^6.0.0",
"@typescript-eslint/parser": "^6.0.0",
"@vitejs/plugin-react": "^4.0.3",
"autoprefixer": "^10.4.16",
"eslint": "^8.45.0",
"eslint-plugin-react-hooks": "^4.6.0",
"eslint-plugin-react-refresh": "^0.4.3",
"postcss": "^8.4.31",
"tailwindcss": "^3.3.5",
"typescript": "^5.0.2",
"vite": "^4.4.5"
}
}
6 changes: 6 additions & 0 deletions examples/postcss.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export default {
plugins: {
tailwindcss: {},
autoprefixer: {},
}
}
1 change: 1 addition & 0 deletions examples/public/vite.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Empty file added examples/src/App.css
Empty file.
182 changes: 182 additions & 0 deletions examples/src/App.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
import { useState, useEffect, useMemo } from 'react'

import './App.css'

import WebRenderer from '@wharfkit/web-renderer';
import SessionKit, { Session } from '@wharfkit/session';
import { WalletPluginWebAuth } from "../../"

const webRenderer = new WebRenderer()

const sessionKit = new SessionKit({
appName: "wharfkit",
chains: [
{
id: "71ee83bcf52142d61019d95f9cc5427ba6a0d7ff8accd9e2088ae2abeaf3d3dd",
url: "https://proton-testnet.eoscafeblock.com",
},
],
ui: webRenderer,
walletPlugins: [
new WalletPluginWebAuth({
scheme: 'proton-dev'
}),
],
})

function App() {
const [sess, setSession] = useState<Session | undefined>(undefined)
const [to, setTo] = useState<string>('')
const [quantity, setQuantity] = useState<string>('')
const [broadcast, setBroadcast] = useState<boolean>(true)

useEffect(() => {
const restoreSession = async () => {
const session = await sessionKit.restore()
setSession(session);
}

restoreSession().catch(console.error);
}, [])

async function login() {
const { session } = await sessionKit.login()
setSession(session)
}

async function logout() {
if(sess) {
await sessionKit.logout()
setSession(undefined);
}
}

const actorName = useMemo(() => {
return sess ? sess.actor.toString() : ''
}, [sess])

const canTransfer = useMemo(() => (+quantity > 0) && to !== '', [quantity, to])

const handleTo = (event: React.FormEvent<HTMLInputElement>) => {
setTo(event.currentTarget.value);
}

const handleQuantity = (event: React.FormEvent<HTMLInputElement>) => {
setQuantity(event.currentTarget.value);
}

const handleBroadcast = (event: React.FormEvent<HTMLInputElement>) => {
setBroadcast(event.currentTarget.checked);
}

async function doTransfer() {
if(sess) {
const data: any = {
account: "eosio.token",
name: "transfer",
authorization: [sess.permissionLevel],
data: {
from: sess.actor,
to: to,
quantity: `${(+quantity).toFixed(4)} XPR`,
memo: "",
},
}

const result2 = await sess.transact({ action: data }, { broadcast })
console.log('Transact result: ', result2);
}
}

return (
<>
<div className="min-h-screen px-3">
<div className="py-2 flex flex-row items-center">
<div className="ml-auto">
{ sess ? (
<>
<span className="mr-2 font-bold">{ actorName }</span>
<button type="button"
className="cursor-pointer whitespace-nowrap text-white bg-purple-700 hover:bg-purple-800 focus:ring-4 focus:ring-purple-300 font-medium rounded-lg text-sm px-5 py-2.5 me-2 mb-2 focus:outline-none"
onClick={logout}>Logout</button>
</>
) : (
<button type="button"
className="cursor-pointer whitespace-nowrap text-white bg-purple-700 hover:bg-purple-800 focus:ring-4 focus:ring-purple-300 font-medium rounded-lg text-sm px-5 py-2.5 me-2 mb-2 focus:outline-none"
onClick={login}>Login</button>
)}
</div>
</div>
<div className="py-2 border-t-2 border-zinc-300">
{
sess && (
<>
<div className="mb-2">
<div>
<label htmlFor="to" className="flex text-sm font-medium text-gray-700">To</label>
<div className="mt-1">
<input
type="text"
name="to"
id="to"
className="outline-none block w-full rounded-md border-0 py-1.5 px-2 text-gray-900 ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-purple-600"
placeholder="e.g. token.burn"
value={to}
onChange={handleTo}
/>
</div>
</div>
</div>

<div className="mb-2">
<label htmlFor="quantity" className="flex text-sm font-medium text-gray-700">Amount</label>
<div className="mt-1">
<input
type="text"
name="quantity"
id="quantity"
className="outline-none block w-full rounded-md border-0 py-1.5 px-2 text-gray-900 ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-purple-600"
placeholder="e.g. 1.3"
value={quantity}
onChange={handleQuantity}
/>
</div>
</div>

<div className="mb-2">
<input
type="checkbox"
name="broadcast"
id="broadcast"
checked={broadcast}
onChange={handleBroadcast}
/>
<label htmlFor="broadcast" className="text-sm font-medium text-gray-700 ml-2">Broadcast</label>
</div>

{ !broadcast &&
<div className="mt-1 mb-2 italic">
Broadcasting disabled. Check transaction info in console.
</div>
}

<div>
<button type="button"
className="cursor-pointer whitespace-nowrap bg-purple-100 border border-transparent rounded-md py-2 px-4 inline-flex items-center justify-center text-base font-medium text-purple-600 hover:bg-purple-200 disabled:bg-zinc-100 disabled:text-zinc-500"
onClick={doTransfer}
disabled={!canTransfer}
>
Transfer
</button>
</div>
</>
)
}
</div>
</div>

</>
)
}

export default App
3 changes: 3 additions & 0 deletions examples/src/index.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
10 changes: 10 additions & 0 deletions examples/src/main.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App.tsx'
import './index.css'

ReactDOM.createRoot(document.getElementById('root')!).render(
<React.StrictMode>
<App />
</React.StrictMode>,
)
1 change: 1 addition & 0 deletions examples/src/vite-env.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/// <reference types="vite/client" />
Loading

0 comments on commit 352829b

Please sign in to comment.