Skip to content

Commit

Permalink
Merge pull request #115 from consensusnetworks/feature/ledger-emulator
Browse files Browse the repository at this point in the history
Add ledger emulator
  • Loading branch information
shanejearley authored Sep 12, 2022
2 parents ff539e4 + f4fae62 commit 9c5c5bd
Show file tree
Hide file tree
Showing 32 changed files with 1,083 additions and 100 deletions.
3 changes: 1 addition & 2 deletions .github/workflows/push.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,7 @@ jobs:
run: npm ci

- name: Build helpers
run: npm run build
working-directory: common/helpers
run: npm run build --workspace @casimir/helpers

- name: Build landing app
run: npm run build --workspace @casimir/landing
Expand Down
12 changes: 12 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
[submodule "scripts/ledger/resources/app-bitcoin"]
path = scripts/ledger/resources/app-bitcoin
url = https://github.com/LedgerHQ/app-bitcoin-new.git
[submodule "scripts/ledger/resources/app-ethereum"]
path = scripts/ledger/resources/app-ethereum
url = https://github.com/LedgerHQ/app-ethereum.git
[submodule "scripts/ledger/resources/app-solana"]
path = scripts/ledger/resources/app-solana
url = https://github.com/LedgerHQ/app-solana.git
[submodule "scripts/ledger/resources/speculos"]
path = scripts/ledger/resources/speculos
url = https://github.com/LedgerHQ/speculos.git
29 changes: 22 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,13 @@ Make sure your development environment has these prerequisites.

1. [Node.js (v16.x)](https://nodejs.org/en/download/) – we use [nvm](https://github.com/nvm-sh/nvm) to manage Node.js versions.

2. [AWS CLI (v2.x)](https://aws.amazon.com/cli/) – create an [AWS profile](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-profiles.html) named `consensus-networks-dev`.
2. [Docker (v4.x)](https://docs.docker.com/engine/install/) - make sure your Docker runs on startup.

3. [SAM CLI (v1.x)](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-install-mac.html) - tool for mocking backend services locally.
3. [AWS CLI (v2.x)](https://aws.amazon.com/cli/) – create an [AWS profile](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-profiles.html) named `consensus-networks-dev`.

4. [SAM CLI (v1.x)](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-install-mac.html) - tool for mocking backend services locally.

> 🚩 You also need to make sure to have at least one SSH authentication key on your GitHub account (for the git cloning of submodules in various scripts). See [Adding a new SSH key to your GitHub account](https://docs.github.com/en/authentication/connecting-to-github-with-ssh/adding-a-new-ssh-key-to-your-github-account).
### Scripts and Dependencies

Expand Down Expand Up @@ -70,7 +74,15 @@ You can get up and running without configuration. You can also mock local backen

> 🚩 You will need the [SAM CLI](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-install-mac.html) for local mocking.

3. The commands and flags above apply to any package in the [apps](apps/) directory. While the default app is [@casimir/web](apps/web/), you can specify others by passing a subcommand to `npm run dev`.
3. Emulate a Ledger hardware wallet with [Speculos](#speculos). The default application is ethereum, and we also currently have support for the bitcoin and solana applications.

```zsh
npm run dev --speculos # or specify --speculos=ethereum, --speculos=bitcoin, or --speculos=solana
```

> 🚩 On MacOS, if you get an error because port 5000 is in use, go to  > System Preferences... > Sharing and uncheck Airplay Receiver.

4. The commands and flags above apply to any package in the [apps](apps/) directory. While the default app is [@casimir/web](apps/web/), you can specify others by passing a subcommand to `npm run dev`.

```zsh
# @casimir/web
Expand Down Expand Up @@ -109,14 +121,17 @@ EVM contract development is serviced through [Hardhat](https://hardhat.io/). The
npm run task:accounts
```

*Todo finish sample flow (show usage of compiled contract ABI in app)*
6. Use a contract in a Casimir app...
6. Use a contract in a Casimir app.

7. Clean [contracts/evm/build/artifacts](contracts/evm/build/artifacts) and [contracts/evm/build/cache](contracts/evm/build/cache)).
```typescript
// Todo add Casimir Typescript usage
```

7. Clean [contracts/evm/build/artifacts](contracts/evm/build/artifacts) and [contracts/evm/build/cache](contracts/evm/build/cache)).

```zsh
npm run task:clean
```
```

> 🚩 Note, this is required if you change the Hardhat configuration.

Expand Down
2 changes: 1 addition & 1 deletion apps/landing/src/composables/users.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export default function useUsers() {
* @returns {string} The base URL for the users API
*/
function getUsersBaseUrl(): string {
if (import.meta.env.PUBLIC_MOCK_ENABLED) {
if (import.meta.env.PUBLIC_MOCK) {
return `http://localhost:${import.meta.env.PUBLIC_USERS_PORT}`
} else {
return `https://users.${import.meta.env.PUBLIC_STAGE || 'dev'}.casimir.co`
Expand Down
3 changes: 2 additions & 1 deletion apps/landing/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ import { createRouter, createWebHistory } from 'vue-router'
import routes from '~pages'

console.log('Creating app...', import.meta.env)
console.log('Local mocking is', import.meta.env.PUBLIC_MOCK_ENABLED ? 'enabled' : 'disabled')
console.log('Local mocking is', import.meta.env.PUBLIC_MOCK ? 'enabled' : 'disabled')
console.log('Ledger emulator is', import.meta.env.PUBLIC_SPECULOS_PORT ? 'enabled' : 'disabled')

const app = createApp(App)
const router = createRouter({
Expand Down
4 changes: 4 additions & 0 deletions apps/web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@
},
"dependencies": {
"@heroicons/vue": "^1.0.6",
"@ledgerhq/hw-app-eth": "^6.29.4",
"@ledgerhq/hw-transport-webhid": "^6.27.2",
"buffer": "^6.0.3",
"ethers": "^5.6.9",
"iotex-antenna": "^0.31.3",
"vue": "^3.2.25",
Expand All @@ -18,6 +21,7 @@
"devDependencies": {
"@esbuild-plugins/node-globals-polyfill": "^0.1.1",
"@esbuild-plugins/node-modules-polyfill": "^0.1.4",
"@rollup/plugin-inject": "^4.0.4",
"@vitejs/plugin-vue": "^2.3.3",
"autoprefixer": "^10.4.7",
"postcss": "^8.4.14",
Expand Down
38 changes: 32 additions & 6 deletions apps/web/src/components/Wallet.vue
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,10 @@
</p>
</div>
<div class="coinbase-div">
<button class="coinbase-btn" @click="connectWallet('CoinbaseWallet')">
<button
class="coinbase-btn"
@click="connectWallet('CoinbaseWallet')"
>
{{ coinbaseButtonText }}
</button>
<p>
Expand All @@ -20,23 +23,42 @@
</p>
</div>
<div class="ioPay-div">
<button class="iopay-btn" @click="connectWallet('IoPay')">
<button
class="iopay-btn"
@click="connectWallet('IoPay')"
>
{{ ioPayButtonText }}
</button>
<p>
Connected ioPay Account:
<span> {{ ioPayAccountsResult }} </span>
</p>
</div>
<button
class="ledger-btn"
@click="connectWallet('Ledger')"
>
Connect Ledger
</button>
</div>
<div class="form-container">
<form @submit.prevent="sendTransaction(selectedProvider)">
<label for="address">Address</label>
<input v-model="toAddress" type="text" placeholder="To Address" />
<br />
<input
v-model="toAddress"
type="text"
placeholder="To Address"
>
<br>
<label for="amount">Amount</label>
<input v-model="amount" type="text" placeholder="Amount Ether" />
<button type="submit">Send Transaction</button>
<input
v-model="amount"
type="text"
placeholder="Amount Ether"
>
<button type="submit">
Send Transaction
</button>
</form>
</div>
</div>
Expand Down Expand Up @@ -127,6 +149,10 @@ button {
background-color: rgb(0, 218, 180);
}
.ledger-btn {
background-color: rgb(0, 0, 0);
}
.connect-wallet-container {
display: flex;
flex-direction: column;
Expand Down
26 changes: 26 additions & 0 deletions apps/web/src/composables/ledger.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import SpeculosHttpTransport from '@casimir/hw-transport-speculos'
import TransportWebHID from '@ledgerhq/hw-transport-webhid'
import Eth from '@ledgerhq/hw-app-eth'

export default function useLedger() {

const bip32Path = '44\'/60\'/0\'/0/0'

async function getLedgerEthSigner() {
const transport = await _getLedgerTransport()
return new Eth(transport)
}

async function _getLedgerTransport() {
if (import.meta.env.PUBLIC_SPECULOS_PORT) {
return await SpeculosHttpTransport.open(`http://127.0.0.1:${import.meta.env.PUBLIC_SPECULOS_PORT}`)
} else {
return await TransportWebHID.create()
}
}

return {
bip32Path,
getLedgerEthSigner
}
}
16 changes: 16 additions & 0 deletions apps/web/src/composables/wallet.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { ref } from 'vue'
import { ethers } from 'ethers'
import useIoPay from '@/composables/iopay'
import useLedger from '@/composables/ledger'
import useEthers from '@/composables/ethers'
import { BrowserProviders } from '@/interfaces/BrowserProviders'
import { EthersProvider } from '@/interfaces/EthersProvider'
Expand All @@ -21,6 +22,7 @@ const ethersProviderList = ['MetaMask', 'CoinbaseWallet']

export default function useWallet() {
const { getIoPayAccounts, sendIoPayTransaction } = useIoPay()
const { bip32Path, getLedgerEthSigner } = useLedger()
const ethereum: any = window.ethereum
const availableProviders = ref<BrowserProviders>(
getBrowserProviders(ethereum)
Expand Down Expand Up @@ -50,6 +52,11 @@ export default function useWallet() {
const accounts = await getIoPayAccounts()
const { address } = accounts[0]
setSelectedAccount(address)
} else if (provider === 'Ledger') {
const ledgerEth = await getLedgerEthSigner()
const { address } = await ledgerEth.getAddress(bip32Path)
console.log(address)
setSelectedAccount(address)
} else {
throw new Error('No provider selected')
}
Expand All @@ -76,6 +83,15 @@ export default function useWallet() {
})
} else if (selectedProvider.value === 'IoPay') {
await sendIoPayTransaction(toAddress.value, amount.value)
} else if (selectedProvider.value === 'Ledger') {

// npm run dev:ethereum in another process
// const ledgerEth = await getLedgerEthSigner()
// Create - { to: ... }
// Serialize - ethers.utils.serializeTransaction
// Sign - ledgerEth.signTransaction
// Send - (new ethers.providers.JsonRpcProvider("http://127.0.0.1:8545")).sendTransaction

} else {
throw new Error('Provider selected not yet supported')
}
Expand Down
2 changes: 1 addition & 1 deletion apps/web/src/types/ProviderString.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
import { BrowserProviders } from '@/interfaces/BrowserProviders'
export type ProviderString = keyof BrowserProviders | 'IoPay' | ''
export type ProviderString = keyof BrowserProviders | 'IoPay' | 'Ledger' |''
16 changes: 8 additions & 8 deletions apps/web/vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,8 @@ import { UserConfig } from 'vite'
import { fileURLToPath } from 'url'
import * as path from 'path'
import pages from 'vite-plugin-pages'

import NodeModulesPolyfills from '@esbuild-plugins/node-modules-polyfill'
import NodeGlobalsPolyfillPlugin from '@esbuild-plugins/node-globals-polyfill'
import inject from '@rollup/plugin-inject'

const config: UserConfig = {
plugins: [
Expand All @@ -14,20 +13,21 @@ const config: UserConfig = {
dirs: [{ dir: 'src/pages', baseRoute: '' }],
extensions: ['vue'],
}),
inject({
Buffer: ['buffer', 'Buffer']
}) as Plugin // https://github.com/rollup/plugins/issues/1243
],
define: {
'window.global': 'globalThis'
'global': 'globalThis'
},
optimizeDeps: {
include: ['iotex-antenna'],
esbuildOptions: {
plugins: [
NodeModulesPolyfills(),
NodeGlobalsPolyfillPlugin({
process: true,
buffer: true,
define: true,
}),
buffer: true
})
],
},
},
Expand All @@ -39,7 +39,7 @@ const config: UserConfig = {
resolve: {
alias: {
'@': path.resolve(path.dirname(fileURLToPath(import.meta.url)), 'src'),
'./runtimeConfig': './runtimeConfig.browser',
'./runtimeConfig': './runtimeConfig.browser'
},
extensions: [
'.js',
Expand Down
2 changes: 2 additions & 0 deletions common/hw-transport-speculos/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
node_modules/
dist/
13 changes: 13 additions & 0 deletions common/hw-transport-speculos/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"name": "@casimir/hw-transport-speculos",
"version": "0.0.1",
"main": "src/index.ts",
"dependencies": {
"@ledgerhq/hw-transport": "^6.27.2"
},
"scripts": {
"dev": "npx esno src/index.ts",
"build": "esbuild src/index.ts --bundle --minify --sourcemap --platform=node --target=esnext --outfile=dist/index.js",
"test": "echo \"Error: no test specified\" && exit 1"
}
}
Loading

0 comments on commit 9c5c5bd

Please sign in to comment.