-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #4 from leapwallet/add-snap-provider
Add snap provider
- Loading branch information
Showing
14 changed files
with
319 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
on: | ||
push: | ||
branches: | ||
- release | ||
paths: | ||
- 'packages/comos-snap-provider' | ||
jobs: | ||
release: | ||
runs-on: ubuntu-latest | ||
env: | ||
NODE_AUTH_TOKEN: ${{ secrets.NODE_AUTH_TOKEN }} | ||
GH_TOKEN: ${{ secrets.NODE_AUTH_TOKEN }} | ||
steps: | ||
- uses: actions/checkout@v2 | ||
- uses: actions/[email protected] | ||
with: | ||
node-version: '16.13.0' | ||
registry-url: 'https://npm.pkg.github.com' | ||
scope: '@leapwallet' | ||
|
||
- name: Build Provider | ||
run: yarn build:provider | ||
|
||
- name: Bump version and publish package | ||
run: | ||
yarn publish --non-interactive |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
# cosmos-snap-provider | ||
|
||
## Usage | ||
|
||
```typescript | ||
import { getSnap, connectSnap, getKey } from '@leapwallet/cosmos-snap-provider' | ||
|
||
async function connect(){ | ||
//check if snap is installed | ||
const snapInstalled = await getSnap() | ||
if(!snapInstalled) { | ||
// Install snap if not already installed | ||
connectSnap() | ||
} | ||
|
||
} | ||
|
||
async function getAccount(){ | ||
await connect() | ||
const chainId = 'cosmoshub-4' | ||
const key = await getKey(chainId) | ||
return key | ||
} | ||
|
||
``` | ||
|
||
## Usage with cosmjs | ||
|
||
```typescript | ||
import { SigningStargateClient } from '@cosmjs/cosmwasm-stargate' | ||
import { GasPrice } from '@cosmjs/stargate' | ||
|
||
|
||
import { cosmjsOfflineSigner } from '@leapwallet/cosmos-snap-provider' | ||
|
||
|
||
|
||
const offlineSigner = new cosmjsOfflineSigner(chainId); | ||
const accounts = await offlineSigner.getAccounts(); | ||
const rpcUrl = "" // Replace with a RPC URL for the given chainId | ||
const stargateClient = await SigningStargateClient.connectWithSigner( | ||
rpcUrl, | ||
offlineSigner, | ||
{ | ||
gasPrice: GasPrice.fromString("0.0025ujuno"), | ||
} | ||
) | ||
|
||
``` | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
{ | ||
"name": "@leapwallet/cosmos-snap-provider", | ||
"packageManager": "[email protected]", | ||
"files": [ | ||
"dist/**/*" | ||
], | ||
"repository": { | ||
"url": "[email protected]:leapwallet/cosmos-metamask-snap.git" | ||
}, | ||
"publishConfig": { | ||
"registry": "https://npm.pkg.github.com" | ||
}, | ||
"scripts": { | ||
"build": "npx tsc", | ||
"start": "npx tsc watch", | ||
"prepublish": "yarn build" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
export {}; | ||
|
||
declare global { | ||
interface Window { | ||
ethereum: any; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
export const defaultSnapOrigin = | ||
process.env.SNAP_ORIGIN ?? `npm:@leapwallet/metamask-cosmos-snap`; |
54 changes: 54 additions & 0 deletions
54
packages/cosmos-snap-provider/src/cosmjs-offline-signer.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
import { SignDoc } from 'cosmjs-types/cosmos/tx/v1beta1/tx'; | ||
import { AccountData, AminoSignResponse } from '@cosmjs/amino'; | ||
import { getKey, requestSignature } from './snap'; | ||
import { DirectSignResponse, OfflineDirectSigner } from '@cosmjs/proto-signing'; | ||
|
||
export class cosmjsOfflineSigner implements OfflineDirectSigner { | ||
constructor(private chainId: string) {} | ||
|
||
async getAccounts(): Promise<AccountData[]> { | ||
const key = await getKey(this.chainId); | ||
return [ | ||
{ | ||
address: key.address, | ||
algo: 'secp256k1', | ||
pubkey: key.pubkey, | ||
}, | ||
]; | ||
} | ||
|
||
async signDirect( | ||
signerAddress: string, | ||
signDoc: SignDoc, | ||
): Promise<DirectSignResponse> { | ||
if (this.chainId !== signDoc.chainId) { | ||
throw new Error('Chain ID does not match signer chain ID'); | ||
} | ||
const accounts = await this.getAccounts(); | ||
|
||
if (accounts.find((account) => account.address !== signerAddress)) { | ||
throw new Error('Signer address does not match wallet address'); | ||
} | ||
|
||
return requestSignature( | ||
this.chainId, | ||
signerAddress, | ||
signDoc, | ||
) as Promise<DirectSignResponse>; | ||
} | ||
|
||
//This has been added as a placeholder. | ||
async signAmino( | ||
signerAddress: string, | ||
signDoc: SignDoc, | ||
): Promise<AminoSignResponse> { | ||
return this.signDirect( | ||
signerAddress, | ||
signDoc, | ||
) as unknown as Promise<AminoSignResponse>; | ||
} | ||
} | ||
|
||
export function getOfflineSigner(chainId: string) { | ||
return new cosmjsOfflineSigner(chainId); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
export * from './snap'; | ||
export * from './types'; | ||
export * from './cosmjs-offline-signer'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,133 @@ | ||
import { AccountData } from '@cosmjs/amino'; | ||
import { defaultSnapOrigin } from './config'; | ||
import { GetSnapsResponse, Snap } from './types'; | ||
import Long from 'long'; | ||
|
||
/** | ||
* Get the installed snaps in MetaMask. | ||
* | ||
* @returns The snaps installed in MetaMask. | ||
*/ | ||
|
||
export const getSnaps = async (): Promise<GetSnapsResponse> => { | ||
return (await window.ethereum.request({ | ||
method: 'wallet_getSnaps', | ||
})) as unknown as GetSnapsResponse; | ||
}; | ||
|
||
/** | ||
* Connect a snap to MetaMask. | ||
* | ||
* @param snapId - The ID of the snap. | ||
* @param params - The params to pass with the snap to connect. | ||
*/ | ||
export const connectSnap = async ( | ||
snapId: string = defaultSnapOrigin, | ||
params: Record<'version' | string, unknown> = {}, | ||
) => { | ||
await window.ethereum.request({ | ||
method: 'wallet_requestSnaps', | ||
params: { | ||
[snapId]: params, | ||
}, | ||
}); | ||
}; | ||
|
||
/** | ||
* Get the snap from MetaMask. | ||
* | ||
* @param version - The version of the snap to install (optional). | ||
* @returns The snap object returned by the extension. | ||
*/ | ||
export const getSnap = async (version?: string): Promise<Snap | undefined> => { | ||
try { | ||
const snaps = await getSnaps(); | ||
|
||
return Object.values(snaps).find( | ||
(snap) => | ||
snap.id === defaultSnapOrigin && (!version || snap.version === version), | ||
); | ||
} catch (e) { | ||
console.log('Failed to obtain installed snap', e); | ||
return undefined; | ||
} | ||
}; | ||
|
||
export const requestSignature = async ( | ||
chainId: string, | ||
signerAddress: string, | ||
signDoc: { | ||
bodyBytes?: Uint8Array | null; | ||
authInfoBytes?: Uint8Array | null; | ||
chainId?: string | null; | ||
accountNumber?: Long | null; | ||
}, | ||
) => { | ||
const signature = await window.ethereum.request({ | ||
method: 'wallet_invokeSnap', | ||
params: { | ||
snapId: defaultSnapOrigin, | ||
request: { | ||
method: 'signDirect', | ||
params: { | ||
chainId, | ||
signerAddress, | ||
signDoc, | ||
}, | ||
}, | ||
}, | ||
}); | ||
|
||
const accountNumber = signDoc.accountNumber; | ||
//@ts-ignore | ||
const modifiedAccountNumber = new Long( | ||
accountNumber!.low, | ||
accountNumber!.high, | ||
accountNumber!.unsigned, | ||
); | ||
|
||
const modifiedSignature = { | ||
//@ts-ignore | ||
signature: signature.signature, | ||
signed: { | ||
// @ts-ignore | ||
...signature.signed, | ||
accountNumber: `${modifiedAccountNumber.toString()}`, | ||
authInfoBytes: new Uint8Array( | ||
//@ts-ignore | ||
Object.values(signature.signed.authInfoBytes), | ||
), | ||
|
||
bodyBytes: new Uint8Array( | ||
//@ts-ignore | ||
Object.values(signature.signed.bodyBytes), | ||
), | ||
}, | ||
}; | ||
|
||
console.log('logging modified signature', modifiedSignature); | ||
return modifiedSignature; | ||
}; | ||
|
||
export const getKey = async (chainId: string): Promise<AccountData> => { | ||
const accountData = await window.ethereum.request({ | ||
method: 'wallet_invokeSnap', | ||
params: { | ||
snapId: defaultSnapOrigin, | ||
request: { | ||
method: 'getKey', | ||
params: { | ||
chainId, | ||
}, | ||
}, | ||
}, | ||
}); | ||
|
||
if (!accountData) throw new Error('No account data found'); | ||
//@ts-ignore | ||
accountData.pubkey = Uint8Array.from(Object.values(accountData.pubkey)); | ||
|
||
return accountData as AccountData; | ||
}; | ||
|
||
export const isLocalSnap = (snapId: string) => snapId.startsWith('local:'); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
export type GetSnapsResponse = Record<string, Snap>; | ||
|
||
export type Snap = { | ||
permissionName: string; | ||
id: string; | ||
version: string; | ||
initialPermissions: Record<string, unknown>; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
{ | ||
"extends": "../../tsconfig.json", | ||
"compilerOptions": { | ||
"outDir": "dist" | ||
}, | ||
|
||
"include": ["src"] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters