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: created sdk-web-evm-connector for integrating 3rd party wallets #103

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .changeset/blue-horses-whisper.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@cypherock/sdk-web-evm-connector': patch
'@cypherock/sdk-hw-webusb': patch
---

created @cypherock/sdk-web-evm-connector for easily integrating 3rd party wallets
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,5 @@ yarn-error.log*

.idea
.fastRequest

.parcel-cache
13 changes: 11 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,21 @@
"@commitlint/config-conventional": "^17.4.4",
"@cypherock/eslint-config": "workspace:*",
"@cypherock/prettier-config": "workspace:*",
"@parcel/packager-ts": "2.12.0",
"@parcel/transformer-typescript-types": "2.12.0",
"husky": "^8.0.0",
"prettier": "^3.2.4",
"turbo": "latest"
"turbo": "latest",
"typescript": ">=3.0.0"
},
"engines": {
"node": ">=18.0.0"
},
"packageManager": "pnpm@7.18.1"
"packageManager": "pnpm@7.18.1",
"pnpm": {
"patchedDependencies": {
"bignumber.js@9.1.2": "patches/bignumber.js@9.1.2.patch",
"long@5.2.1": "patches/long@5.2.1.patch"
}
}
}
24 changes: 21 additions & 3 deletions packages/hw-webusb/src/deviceConnection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {
} from '@cypherock/sdk-interfaces';
import * as uuid from 'uuid';

import { createPort, DataListener } from './helpers';
import { requestDevice, DataListener, getAvailableDevices } from './helpers';

export default class DeviceConnection implements IDeviceConnection {
protected deviceState: DeviceState;
Expand Down Expand Up @@ -43,9 +43,27 @@ export default class DeviceConnection implements IDeviceConnection {
return new DeviceConnection(connection, dataListener);
}

public static async list() {
return getAvailableDevices();
}

public static async requestDevice() {
return requestDevice();
}

public static async create() {
const connection = await createPort();
return DeviceConnection.connect(connection);
const devices = await getAvailableDevices();

if (devices.length > 0) {
return DeviceConnection.connect(devices[0]);
}

const device = await requestDevice();
return DeviceConnection.connect(device);
}

public getDevice() {
return this.connection;
}

public async getDeviceState() {
Expand Down
23 changes: 22 additions & 1 deletion packages/hw-webusb/src/helpers/connection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,23 @@ const supportedDevices: USBDeviceFilter[] = [
{ vendorId: 0x3503, productId: 259 },
];

const isUSBDeviceSupported = (device: USBDevice) => {
const { vendorId, productId } = device;

for (const supportedDevice of supportedDevices) {
if (
supportedDevice.vendorId === vendorId &&
supportedDevice.productId === productId
) {
return true;
}
}

return false;
};

// eslint-disable-next-line
export const createPort = async () => {
export const requestDevice = async () => {
const connectionInfo = await navigator.usb.requestDevice({
filters: supportedDevices,
});
Expand All @@ -19,3 +34,9 @@ export const createPort = async () => {

return connectionInfo;
};

export const getAvailableDevices = async () => {
const allDevices = await navigator.usb.getDevices();

return allDevices.filter(d => isUSBDeviceSupported(d));
};
30 changes: 30 additions & 0 deletions packages/web-evm-connector/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.

# dependencies
/node_modules
/.pnp
.pnp.js

# testing
/coverage

/out/

# production
/build

# misc
.DS_Store
*.pem

# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*
.pnpm-debug.log*

# local env files
.env*.local

dist
.turbo
1 change: 1 addition & 0 deletions packages/web-evm-connector/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# Cypherock EVM Connector for WebApps
38 changes: 38 additions & 0 deletions packages/web-evm-connector/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
{
"name": "@cypherock/sdk-web-evm-connector",
"version": "0.0.0",
"private": false,
"source": "src/index.ts",
"module": "dist/index.js",
"types": "dist/types.d.ts",
"scripts": {
"build:types": "dts-bundle-generator --config type.config.json",
"build": "pnpm clean && node ./scripts/build.js && pnpm build:types",
"clean": "rimraf dist",
"start": "node ./scripts/serve.js",
"analyze": "node ./scripts/analyze.js"
},
"devDependencies": {
"@cypherock/sdk-app-evm": "workspace:^",
"@cypherock/sdk-app-manager": "workspace:^",
"@cypherock/sdk-core": "workspace:^",
"@cypherock/sdk-hw-webusb": "workspace:^",
"@cypherock/sdk-interfaces": "workspace:^",
"@cypherock/sdk-utils": "workspace:^",
"@types/w3c-web-usb": "^1.0.6",
"cross-env": "^7.0.3",
"dts-bundle-generator": "^9.3.1",
"eip-712": "^1.0.0",
"esbuild": "^0.20.1",
"esbuild-plugin-tsc": "^0.4.0",
"ethers": "^6.7.0",
"rimraf": "^4.1.2",
"typescript": "4.9.5"
},
"files": [
"dist",
".gitignore",
"README.md",
"package.json"
]
}
21 changes: 21 additions & 0 deletions packages/web-evm-connector/scripts/analyze.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
const esbuild = require('esbuild');
const fs = require('node:fs');
const { createBuildSettings } = require('./settings.js');

const run = async () => {
const settings = createBuildSettings({ minify: true, metafile: true });
const result = await esbuild.build(settings);
const mode = process.env.npm_config_mode;

if (mode === 'write') {
fs.writeFileSync('build-meta.json', JSON.stringify(result.metafile));
} else {
esbuild
.analyzeMetafile(result.metafile, {
verbose: false,
})
.then(console.log);
}
};

run();
10 changes: 10 additions & 0 deletions packages/web-evm-connector/scripts/build.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
const esbuild = require('esbuild');
const { createBuildSettings } = require('./settings.js');

const settings = createBuildSettings({ minify: true });

esbuild
.build({
...settings,
})
.then(console.log);
15 changes: 15 additions & 0 deletions packages/web-evm-connector/scripts/settings.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
function createBuildSettings(options) {
return {
entryPoints: ['src/index.ts'],
outfile: 'dist/index.js',
bundle: true,
plugins: [],
platform: 'browser',
format: 'esm',
minify: true,
treeShaking: true,
...options,
};
}

module.exports = { createBuildSettings };
80 changes: 80 additions & 0 deletions packages/web-evm-connector/src/derivationScheme.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
export type IDerivationPathGenerator = (
from: number,
count: number,
) => { derivationPath: string; index: number }[];

export const createDerivationPathGenerator =
(basePath: string): IDerivationPathGenerator =>
(from, count) => {
const derivationPaths: { derivationPath: string; index: number }[] = [];

let startIndex = from;

while (derivationPaths.length < count) {
const nextDerivationPath = basePath.replace('i', startIndex.toString());

derivationPaths.push({
derivationPath: nextDerivationPath,
index: startIndex,
});

if (!basePath.includes('i')) break;

startIndex += 1;
}

return derivationPaths;
};

export const EvmDerivationSchemeMap = {
ledger: 'ledger',
metamask: 'metamask',
legacy: 'legacy',
} as const;

export type EvmDerivationSchemeName =
(typeof EvmDerivationSchemeMap)[keyof typeof EvmDerivationSchemeMap];

export interface IEvmDerivationScheme {
name: EvmDerivationSchemeName;
generator: IDerivationPathGenerator;
}

export const derivationPathSchemes: Record<
EvmDerivationSchemeName,
IEvmDerivationScheme
> = {
ledger: {
name: 'ledger',
generator: createDerivationPathGenerator("m/44'/60'/i'/0/0"),
},
metamask: {
name: 'metamask',
generator: createDerivationPathGenerator("m/44'/60'/0'/0/i"),
},
legacy: {
name: 'legacy',
generator: createDerivationPathGenerator("m/44'/60'/0'/i"),
},
};

export const mapDerivationPathForSdk = (derivationPath: string) => {
const paths: number[] = [];

const pathArr = derivationPath.split('/');

for (const path of pathArr) {
if (path !== 'm') {
const isHardened = path.includes("'");
let index = parseInt(path.replace("'", ''), 10);

if (isHardened) {
index += 0x80000000;
}

paths.push(index);
}
}

return paths;
};
Loading
Loading