Skip to content

Commit

Permalink
fix: update dialogs to JSX and some minor improvements to the UI
Browse files Browse the repository at this point in the history
  • Loading branch information
hugomrdias committed Sep 26, 2024
1 parent ca2bb6d commit 18dd299
Show file tree
Hide file tree
Showing 11 changed files with 272 additions and 201 deletions.
2 changes: 1 addition & 1 deletion packages/snap/snap.manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"url": "https://github.com/filecoin-project/filsnap.git"
},
"source": {
"shasum": "V9ppgok3FzDbCzybXL9IUQCZzm5YFuq9n7O582xueEo=",
"shasum": "Sfp8JZTgJ26Ypg2PVwey/XUDbuiJfq4jWBaxyMjN40s=",
"location": {
"npm": {
"filePath": "dist/snap.js",
Expand Down
26 changes: 12 additions & 14 deletions packages/snap/src/account.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import { getBIP44AddressKeyDeriver } from '@metamask/key-tree'
import type { SnapsProvider } from '@metamask/snaps-sdk'
import type { AddressBLS, AddressSecp256k1 } from 'iso-filecoin/address'
import { parseDerivationPath } from 'iso-filecoin/utils'
import { accountFromPrivateKey } from 'iso-filecoin/wallet'
import type { Account, SnapConfig } from './types'
import type { AccountPrivate, AccountSafe, SnapConfig } from './types'

/**
* Return derived Account from seed.
Expand All @@ -14,7 +13,7 @@ import type { Account, SnapConfig } from './types'
export async function getAccount(
snap: SnapsProvider,
config: SnapConfig
): Promise<Account> {
): Promise<AccountPrivate> {
const { derivationPath } = config
const { coinType, account, change, addressIndex } =
parseDerivationPath(derivationPath)
Expand All @@ -38,11 +37,14 @@ export async function getAccount(
}
const privateKeyBuffer = privateKey.subarray(0, 32)

return accountFromPrivateKey(
privateKeyBuffer,
'SECP256K1',
isFilecoinMainnet ? 'mainnet' : 'testnet'
)
return {
...accountFromPrivateKey(
privateKeyBuffer,
'SECP256K1',
isFilecoinMainnet ? 'mainnet' : 'testnet'
),
accountNumber: account,
}
}

/**
Expand All @@ -54,11 +56,7 @@ export async function getAccount(
export async function getAccountSafe(
snap: SnapsProvider,
config: SnapConfig
): Promise<{
address: AddressSecp256k1 | AddressBLS
pubKey: Uint8Array
accountNumber: number
}> {
): Promise<AccountSafe> {
const { derivationPath } = config
const {
coinType,
Expand Down Expand Up @@ -98,5 +96,5 @@ export async function getAccountSafe(
// @ts-expect-error - deref account
account = null

return { address, pubKey, accountNumber }
return { address, pubKey, accountNumber, path: account.path }
}
50 changes: 50 additions & 0 deletions packages/snap/src/components/configure.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import {
Bold,
Box,
Copyable,
Heading,
Row,
type SnapComponent,
Text,
} from '@metamask/snaps-sdk/jsx'
import type { SnapConfig } from '../types'

type ConfigureProps = {
origin: string
address: string
accountNumber: number
config: SnapConfig
}

export const Configure: SnapComponent<ConfigureProps> = ({
address,
origin,
accountNumber,
config,
}) => {
return (
<Box>
<Heading>Connection request</Heading>
<Text>
<Bold>{origin}</Bold> wants to connect with your Filecoin account.
</Text>
<Text>Account {accountNumber.toString()}</Text>
<Copyable value={address} />
<Row label="Derivation Path:">
<Text>{config.derivationPath}</Text>
</Row>
<Row label="API:">
<Text>{config.rpc.url}</Text>
</Row>
<Row label="Network:">
<Text>{config.network}</Text>
</Row>
<Row label="Unit Decimals:">
<Text>{config.unit?.decimals.toString() ?? 'N/A'}</Text>
</Row>
<Row label="Unit Symbol:">
<Text>{config.unit?.symbol ?? 'N/A'}</Text>
</Row>
</Box>
)
}
45 changes: 45 additions & 0 deletions packages/snap/src/components/export.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import {
Bold,
Box,
Copyable,
Heading,
type SnapComponent,
Text,
} from '@metamask/snaps-sdk/jsx'

type ExportConfirmProps = {
address: string
accountNumber: number
}

export const ExportConfirm: SnapComponent<ExportConfirmProps> = ({
address,
accountNumber,
}) => {
return (
<Box>
<Heading>Private Key Export Request</Heading>
<Text>
Do you want to export <Bold>Account {accountNumber.toString()}</Bold>{' '}
private key ?
</Text>
<Text>Address:</Text>
<Copyable value={address} />
</Box>
)
}

type PrivateKeyExportProps = {
privateKey: string
}

export const PrivateKeyExport: SnapComponent<PrivateKeyExportProps> = ({
privateKey,
}) => {
return (
<Box>
<Heading>Private Key</Heading>
<Copyable value={privateKey} />
</Box>
)
}
89 changes: 89 additions & 0 deletions packages/snap/src/components/sign.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import {
Bold,
Box,
Copyable,
Heading,
Row,
type SnapComponent,
Text,
} from '@metamask/snaps-sdk/jsx'
import type { Message } from 'iso-filecoin/message'
import { Token } from 'iso-filecoin/token'
import type { Jsonify } from 'type-fest'
import type { SnapConfig } from '../types'
import { formatFIL } from '../utils'

type SignMessageDialogProps = {
origin: string
accountNumber: number
message: Jsonify<Message>
config: SnapConfig
}

export const SignMessageDialog: SnapComponent<SignMessageDialogProps> = ({
accountNumber,
message,
config,
origin,
}) => {
const gas = Token.fromAttoFIL(message.gasPremium).mul(message.gasLimit)
const total = Token.fromAttoFIL(message.value).add(gas)

return (
<Box>
<Heading>Signature Request from {origin}</Heading>
<Row label="Send">
<Text>
<Bold>{formatFIL(message.value, config)}</Bold>
</Text>
</Row>
<Row
label="From"
tooltip={`Account
${accountNumber.toString()}`}
>
<Text>{message.from}</Text>
</Row>
<Row label="To">
<Text>{message.to}</Text>
</Row>
<Heading>Details</Heading>
<Row label="Gas" tooltip="Estimated gas">
<Text>{formatFIL(gas, config)}</Text>
</Row>

<Row label="Total" tooltip="Estimated total (amount + gas)">
<Text>{formatFIL(total, config)}</Text>
</Row>
<Row label="API">
<Text> {config.rpc.url}</Text>
</Row>
<Row label="Network">
<Text> {config.network}</Text>
</Row>
</Box>
)
}

type SignRawDialogProps = {
origin: string
accountNumber: number
message: string
}

export const SignRawDialog: SnapComponent<SignRawDialogProps> = ({
accountNumber,
origin,
message,
}) => {
return (
<Box>
<Heading>Signature Request from {origin}</Heading>
<Text>
Do you want to sign the message below with{' '}
<Bold>Account {accountNumber.toString()}</Bold>?
</Text>
<Copyable value={message} />
</Box>
)
}
1 change: 1 addition & 0 deletions packages/snap/src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ export const onRpcRequest: OnRpcRequestHandler = async ({
request.params as SignMessageRawParams
)
}

case 'fil_sendMessage': {
return await sendMessage(context, request.params as SignedMessage)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import { copyable, heading, panel, row, text } from '@metamask/snaps-sdk'
import { dequal } from 'dequal/lite'
import { RPC } from 'iso-filecoin/rpc'
import { parseDerivationPath } from 'iso-filecoin/utils'

// @ts-expect-error - no types for this package
import merge from 'merge-options'
import { getAccountSafe } from '../account'
import { Configure } from '../components/configure'
import { snapConfig } from '../schemas'
import type { SnapConfig, SnapContext, SnapResponse } from '../types'
import { configFromNetwork, serializeError, snapDialog } from '../utils'
import { configFromNetwork, serializeError } from '../utils'

// Types
export type ConfigureParams = Partial<SnapConfig>
Expand Down Expand Up @@ -42,7 +42,6 @@ export async function configure(
derivationPath,
rpc: { url, token },
network,
unit,
} = _params.data

const { coinType, account: accountNumber } =
Expand Down Expand Up @@ -81,19 +80,19 @@ export async function configure(

const account = await getAccountSafe(snap, _params.data)

const conf = await snapDialog(ctx.snap, {
type: 'confirmation',
content: panel([
heading('Connection request'),
text(`**${ctx.origin}** wants to connect with your Filecoin account.`),
text(`Account ${accountNumber}`),
copyable(`${account.address.toString()}`),
row('Derivation Path:', text(derivationPath)),
row('API:', text(url)),
row('Network:', text(network)),
row('Unit Decimals:', text(unit?.decimals.toString() ?? 'N/A')),
row('Unit Symbol:', text(unit?.symbol ?? 'N/A')),
]),
const conf = await ctx.snap.request({
method: 'snap_dialog',
params: {
type: 'confirmation',
content: (
<Configure
accountNumber={accountNumber}
address={account.address.toString()}
config={_params.data}
origin={ctx.origin}
/>
),
},
})

if (conf) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import { copyable, divider, panel, text } from '@metamask/snaps-sdk'
import { base64pad } from 'iso-base/rfc4648'
import { parseDerivationPath } from 'iso-filecoin/utils'
import { getAccount } from '../account'
import { ExportConfirm, PrivateKeyExport } from '../components/export'
import type { SnapContext, SnapResponse } from '../types'
import { serializeError, snapDialog } from '../utils'
import { serializeError } from '../utils'

// Types
export type ExportPrivateKeyResponse = SnapResponse<boolean>
Expand Down Expand Up @@ -31,29 +30,28 @@ export async function exportPrivateKey(

const account = await getAccount(snap, config)

const { account: accountNumber } = parseDerivationPath(config.derivationPath)
const conf = await snapDialog(ctx.snap, {
type: 'confirmation',
content: panel([
text(
`Do you want to export **Account ${accountNumber}** _${account.address.toString()}_ your private key?`
const conf = await ctx.snap.request({
method: 'snap_dialog',
params: {
type: 'confirmation',
content: (
<ExportConfirm
address={account.address.toString()}
accountNumber={account.accountNumber}
/>
),
divider(),
text(
'Warning: Never disclose this key. Anyone with your private keys can steal any assets held in your account.'
),
]),
},
})

if (conf) {
await snapDialog(ctx.snap, {
type: 'alert',
content: panel([
text(
`Private key for **Account ${accountNumber}** _${account.address.toString()}_`
await ctx.snap.request({
method: 'snap_dialog',
params: {
type: 'alert',
content: (
<PrivateKeyExport privateKey={base64pad.encode(account.privateKey)} />
),
copyable(base64pad.encode(account.privateKey)),
]),
},
})

return { result: true, error: null }
Expand Down
Loading

0 comments on commit 18dd299

Please sign in to comment.