Skip to content

Commit

Permalink
new module for ledger related utils (#193)
Browse files Browse the repository at this point in the history
* new module for ledger related utils

* pass with not tests

* Add method docs

* changeset

* Switch to offline signer implementation instead

* Address review comments
  • Loading branch information
dssei authored Aug 21, 2024
1 parent 35c62d0 commit c0cd7a0
Show file tree
Hide file tree
Showing 15 changed files with 1,270 additions and 11 deletions.
5 changes: 5 additions & 0 deletions .changeset/silver-bugs-itch.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@sei-js/ledger': minor
---

Packge init + helper functions to work with Ledger in Cosmos Stargate client
2 changes: 2 additions & 0 deletions packages/ledger/.eslintignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
node_modules
dist
Empty file added packages/ledger/.gitkeep
Empty file.
13 changes: 13 additions & 0 deletions packages/ledger/.npmignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
src
node_modules
docs
coverage/

.gitkeep
jest.config.ts
tsconfig.json

yarn-error.log

.eslintignore
eslintrc.json
52 changes: 52 additions & 0 deletions packages/ledger/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# @sei-js/ledger

## Installation
```bash
yarn add @sei-js/ledger
```

## Usage
```typescript
import {
coins,
SigningStargateClient,
StdFee
} from "@cosmjs/stargate";

import {
createTransportAndApp,
getAddresses,
SeiLedgerOfflineAminoSigner
} from "@sei-js/ledger";

const testApp = async () => {
const validatorAddress = "seivaloper1sq7x0r2mf3gvwr2l9amtlye0yd3c6dqa4th95v";
const rpcUrl = "https://rpc-testnet.sei-apis.com/";
const memo = "Delegation";
const path = "m/44'/60'/0'/0/0";

const {app} = await createTransportAndApp();
const {nativeAddress} = await getAddresses(app, path);
const ledgerSigner = new SeiLedgerOfflineAminoSigner(app, path)
const signingStargateClient = await SigningStargateClient.connectWithSigner(rpcUrl, ledgerSigner)

const msgDelegate = {
typeUrl: "/cosmos.staking.v1beta1.MsgDelegate",
value: {
delegatorAddress: nativeAddress.address,
validatorAddress: validatorAddress,
amount: coins(500, "usei"),
},
};

const fee: StdFee = {
amount: [{denom: "usei", amount: "20000"}],
gas: "200000",
};

const result = await signingStargateClient.signAndBroadcast(nativeAddress.address, [msgDelegate], fee, memo)
console.log("Broadcast result:", result);
};

testApp();
```
3 changes: 3 additions & 0 deletions packages/ledger/eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"extends": ["../../eslint.base.json", "eslint:recommended", "plugin:@typescript-eslint/recommended"]
}
8 changes: 8 additions & 0 deletions packages/ledger/jest.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
/** @type {import('ts-jest').JestConfigWithTsJest} */
module.exports = {
preset: 'ts-jest',
testEnvironment: 'node',
testMatch: ['**/__tests__/**/*.ts?(x)', '**/?(*.)+(spec|test).ts?(x)'],
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node'],
modulePathIgnorePatterns: ['<rootDir>/dist/']
};
50 changes: 50 additions & 0 deletions packages/ledger/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
{
"name": "@sei-js/ledger",
"version": "1.0.0",
"description": "TypeScript library for SEI Ledger app helper functions",
"main": "./dist/cjs/src/index.js",
"module": "./dist/esm/src/index.js",
"types": "./dist/types/src/index.d.ts",
"sideEffects": false,
"files": [
"dist"
],
"scripts": {
"prebuild": "rimraf dist",
"build": "yarn build:cjs && yarn build:esm && yarn build:prettier && yarn build:types",
"build:cjs": "tsc --outDir dist/cjs --module commonjs",
"build:esm": "tsc --outDir dist/esm --module esnext",
"build:types": "tsc --project ./tsconfig.declaration.json",
"build:prettier": "prettier --write 'dist/**/*.js'",
"docs": "typedoc --out docs",
"test": "jest --passWithNoTests",
"lint": "eslint --ext .ts"
},
"homepage": "https://github.com/sei-protocol/sei-js#readme",
"keywords": [
"sei",
"javascript",
"typescript",
"ledger"
],
"repository": "[email protected]:sei-protocol/sei-js.git",
"license": "MIT",
"private": false,
"publishConfig": {
"access": "public"
},
"dependencies": {
"@cosmjs/stargate": "^0.32.4",
"@ledgerhq/hw-transport-node-hid": "^6.29.3",
"@zondax/ledger-sei": "^1.0.0"
},
"peerDependencies": {},
"devDependencies": {},
"exports": {
".": {
"import": "./dist/esm/src/index.js",
"require": "./dist/cjs/src/index.js",
"types": "./dist/types/src/index.d.ts"
}
}
}
2 changes: 2 additions & 0 deletions packages/ledger/src/cosmos/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from "./seiLedgerOfflineAminoSigner"
export * from "./utils"
50 changes: 50 additions & 0 deletions packages/ledger/src/cosmos/seiLedgerOfflineAminoSigner.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import {
AminoSignResponse,
encodeSecp256k1Signature,
OfflineAminoSigner,
serializeSignDoc,
StdSignDoc
} from '@cosmjs/amino';
import {fromHex } from '@cosmjs/encoding';
import { AccountData } from '@cosmjs/proto-signing';
import { Secp256k1Signature } from '@cosmjs/crypto';
import { SeiApp } from '@zondax/ledger-sei';

/**
* A signer implementation that uses a Ledger device to sign transactions
*/
export class SeiLedgerOfflineAminoSigner implements OfflineAminoSigner {
private readonly path: string;
private readonly app: SeiApp;

/**
* Creates a new SeiLedgerOfflineAminoSigner
* @param app Ledger Sei app instance
* @param path hd derivation path (e.g. "m/44'/60'/0'/0/0")
*/
constructor(app: SeiApp, path: string) {
this.path = path;
this.app = app;
}

public async getAccounts(): Promise<readonly AccountData[]> {
const nativeAddress = await this.app.getCosmosAddress(this.path);
return [
{
address: nativeAddress.address,
algo: "secp256k1",
pubkey: fromHex(nativeAddress.pubKey)
},
];
}

public async signAmino(signerAddress: string, signDoc: StdSignDoc): Promise<AminoSignResponse> {
const signature = await this.app.signCosmos(this.path, Buffer.from(serializeSignDoc(signDoc)));
const sig = new Secp256k1Signature(signature.r, signature.s).toFixedLength();
const nativeAddress = await this.app.getCosmosAddress(this.path);
return {
signed: signDoc,
signature: encodeSecp256k1Signature(fromHex(nativeAddress.pubKey), sig),
};
}
}
28 changes: 28 additions & 0 deletions packages/ledger/src/cosmos/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import Transport from '@ledgerhq/hw-transport-node-hid';
import { SeiApp } from '@zondax/ledger-sei';

/**
* Creates a transport and app instance
*
* @returns {Promise<{transport: Transport, app: SeiApp}>} transport and app instances
*/
export const createTransportAndApp = async () => {
const transport = await Transport.create();
const app = new SeiApp(transport);
return {transport, app};
};

/**
* Get the EVM and Cosmos addresses from the Ledger device
* @param app Ledger Sei app instance
* @param path hd derivation path (e.g. "m/44'/60'/0'/0/0")
*
* @returns {Promise<{evmAddress: string, nativeAddress: string}>} EVM and Cosmos address objects containing
* address and public key
*/
export const getAddresses = async (app: SeiApp, path: string) => {
const evmAddress = await app.getEVMAddress(path);
const nativeAddress = await app.getCosmosAddress(path);
return {evmAddress, nativeAddress};
};

1 change: 1 addition & 0 deletions packages/ledger/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './cosmos';
10 changes: 10 additions & 0 deletions packages/ledger/tsconfig.declaration.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "./dist/types",
"declaration": true,
"emitDeclarationOnly": true,
"isolatedModules": false,
"preserveConstEnums": false
}
}
13 changes: 13 additions & 0 deletions packages/ledger/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"extends": "../../tsconfig.base.json",
"include": ["./src/**/*" ],
"compilerOptions": {
"outDir": "./dist/types",
"rootDir": "./",
},
"typedocOptions": {
"readme": "./README.md",
"name": "registry",
"entryPoints": ["src/index.ts"]
}
}
Loading

0 comments on commit c0cd7a0

Please sign in to comment.