Skip to content

Commit

Permalink
refactor: sdk tweaks and add to walletd
Browse files Browse the repository at this point in the history
  • Loading branch information
alexfreska committed Mar 30, 2024
1 parent 815ef68 commit d26a952
Show file tree
Hide file tree
Showing 19 changed files with 126 additions and 58 deletions.
5 changes: 5 additions & 0 deletions .changeset/fast-suits-punch.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@siafoundation/sdk': minor
---

signTransaction has been updated to the more specific signTransactionV1.
5 changes: 5 additions & 0 deletions .changeset/honest-falcons-rhyme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@siafoundation/sdk': minor
---

WebTransportClient no longer requires the SDK API as an explicit constructor parameter.
9 changes: 7 additions & 2 deletions .github/workflows/pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,14 @@ jobs:
uses: golangci/golangci-lint-action@v3
with:
skip-cache: true
- name: NX pre-build compile targets
# The SDK is referenced via dist in the tsconfig.base.json
# because the next executor does not actually support
# buildLibsFromSource=false
# With this configuration NX does not build the SDK as expected
# when it is an app dependency
- name: Force build SDK
shell: bash
run: npx nx affected --target=compile --parallel=5
run: npx nx run sdk:build
- name: Test TypeScript
shell: bash
run: npx nx affected --target=test --parallel=5
Expand Down
9 changes: 7 additions & 2 deletions .github/workflows/release-main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,14 @@ jobs:
uses: golangci/golangci-lint-action@v3
with:
skip-cache: true
- name: NX pre-build compile targets
# The SDK is referenced via dist in the tsconfig.base.json
# because the next executor does not actually support
# buildLibsFromSource=false
# With this configuration NX does not build the SDK as expected
# when it is an app dependency
- name: Force build SDK
shell: bash
run: npx nx run-many --target=compile --all --parallel=5
run: npx nx run sdk:build
- name: Test TypeScript
shell: bash
run: npx nx run-many --target=test --all --parallel=5
Expand Down
4 changes: 2 additions & 2 deletions apps/walletd-e2e/project.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"$schema": "../../node_modules/nx/schemas/project-schema.json",
"sourceRoot": "apps/walletd-e2e/src",
"projectType": "application",
"implicitDependencies": ["walletd"],
"targets": {
"e2e": {
"executor": "@nx/playwright:playwright",
Expand All @@ -14,6 +15,5 @@
"lint": {
"executor": "@nx/eslint:lint"
}
},
"implicitDependencies": ["walletd"]
}
}
29 changes: 16 additions & 13 deletions apps/walletd/config/providers.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,26 +4,29 @@ import { WalletsProvider } from '../contexts/wallets'
import { AddressesProvider } from '../contexts/addresses'
import { EventsProvider } from '../contexts/events'
import { LedgerProvider } from '../contexts/ledger'
import { AppProvider } from '../contexts/app'

type Props = {
children: React.ReactNode
}

export function Providers({ children }: Props) {
return (
<DialogProvider>
<LedgerProvider>
<WalletsProvider>
<AddressesProvider>
<EventsProvider>
{/* this is here so that dialogs can use all the other providers,
<AppProvider>
<DialogProvider>
<LedgerProvider>
<WalletsProvider>
<AddressesProvider>
<EventsProvider>
{/* this is here so that dialogs can use all the other providers,
and the other providers can trigger dialogs */}
<Dialogs />
{children}
</EventsProvider>
</AddressesProvider>
</WalletsProvider>
</LedgerProvider>
</DialogProvider>
<Dialogs />
{children}
</EventsProvider>
</AddressesProvider>
</WalletsProvider>
</LedgerProvider>
</DialogProvider>
</AppProvider>
)
}
27 changes: 27 additions & 0 deletions apps/walletd/contexts/app/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { createContext, useContext, useEffect } from 'react'
import { initSDK } from '@siafoundation/sdk'

function useAppMain() {
// Initialize the SDK on app load
useEffect(() => {
const func = async () => {
await initSDK()
}
func()
}, [])
return {}
}

type State = ReturnType<typeof useAppMain>

const AppContext = createContext({} as State)
export const useApp = () => useContext(AppContext)

type Props = {
children: React.ReactNode
}

export function AppProvider({ children }: Props) {
const state = useAppMain()
return <AppContext.Provider value={state}>{children}</AppContext.Provider>
}
2 changes: 2 additions & 0 deletions apps/walletd/project.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"$schema": "../../node_modules/nx/schemas/project-schema.json",
"sourceRoot": "apps/walletd",
"projectType": "application",
"implicitDependencies": ["sdk"],
"targets": {
"build": {
"executor": "@nx/next:build",
Expand Down Expand Up @@ -67,6 +68,7 @@
"test": {
"executor": "@nx/jest:jest",
"outputs": ["{workspaceRoot}/coverage/apps/walletd"],
"dependsOn": ["sdk:build"],
"options": {
"jestConfig": "apps/walletd/jest.config.ts"
}
Expand Down
4 changes: 1 addition & 3 deletions libs/sdk/project.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@
"projectType": "library",
"tags": [],
"namedInputs": {
"go": ["{workspaceRoot}/sdk/**/*"],
"production": ["default", "go"]
"go": ["{workspaceRoot}/sdk/**/*"]
},
"targets": {
"compile": {
Expand All @@ -24,7 +23,6 @@
"executor": "@nx/rollup:rollup",
"outputs": ["{options.outputPath}"],
"dependsOn": ["compile", "^build"],
"inputs": ["production", "^production"],
"options": {
"outputPath": "dist/libs/sdk",
"tsConfig": "libs/sdk/tsconfig.lib.json",
Expand Down
4 changes: 3 additions & 1 deletion libs/sdk/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
export * from './init'
export * from './types'
export { initSDK } from './init'
export { getSDK } from './sdk'
export type { SDK } from './sdk'
20 changes: 15 additions & 5 deletions libs/sdk/src/sdk.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,22 @@
import { WebTransportClient } from './transport'
import { WASM } from './types'
import { WasmApi } from './types'

export function getSDK() {
export type SDK = WasmApi & {
WebTransportClient: typeof WebTransportClient
}

export function getWasmApi(): WasmApi {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const wasm = (global as any).sia as WASM
return (globalThis as any).sia as WasmApi
}

export function getSDK(): SDK {
const wasmApi = getWasmApi()
if (wasmApi === undefined) {
throw new Error('The Sia SDK has not been initialized')
}
return {
rhp: wasm.rhp,
wallet: wasm.wallet,
...wasmApi,
WebTransportClient,
}
}
26 changes: 14 additions & 12 deletions libs/sdk/src/transport.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { getWasmApi } from './sdk'
import {
RPCReadSectorResponse,
RPCSettingsResponse,
Expand All @@ -9,26 +10,27 @@ import {
RPCWriteSector,
RPCSettings,
} from './types'
import { WASM } from './types'

export class WebTransportClient {
#url: string
#cert: string
#wasm: WASM

#transport!: WebTransport

constructor(url: string, cert: string, wasm: WASM) {
constructor(url: string, cert: string) {
this.#url = url
this.#cert = cert
this.#wasm = wasm
}

async connect() {
if (!getWasmApi()) {
throw new Error('The Sia SDK has not been initialized.')
}

if (!('WebTransport' in window)) {
throw new Error('WebTransport is not supported in your browser.')
}
}

async connect() {
try {
this.#transport = new WebTransport(this.#url, {
serverCertificateHashes: this.#cert
Expand Down Expand Up @@ -101,8 +103,8 @@ export class WebTransportClient {
): Promise<RPCReadSectorResponse> {
return this.sendRequest<RPCReadSector>(
readSector,
this.#wasm.rhp.encodeReadSectorRequest,
this.#wasm.rhp.decodeReadSectorResponse
getWasmApi().rhp.encodeReadSectorRequest,
getWasmApi().rhp.decodeReadSectorResponse
)
}

Expand All @@ -111,16 +113,16 @@ export class WebTransportClient {
): Promise<RPCWriteSectorResponse> {
return this.sendRequest<RPCWriteSector>(
writeSector,
this.#wasm.rhp.encodeWriteSectorRequest,
this.#wasm.rhp.decodeWriteSectorResponse
getWasmApi().rhp.encodeWriteSectorRequest,
getWasmApi().rhp.decodeWriteSectorResponse
)
}

async sendRPCSettingsRequest(): Promise<RPCSettingsResponse> {
return this.sendRequest<RPCSettings>(
undefined,
this.#wasm.rhp.encodeSettingsRequest,
this.#wasm.rhp.decodeSettingsResponse
getWasmApi().rhp.encodeSettingsRequest,
getWasmApi().rhp.decodeSettingsResponse
)
}
}
Expand Down
17 changes: 8 additions & 9 deletions libs/sdk/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,14 @@ import {
UnlockConditions,
ConsensusNetwork,
ConsensusState,
Currency,
Signature,
Address,
Hash256,
PublicKey,
PrivateKey,
} from '@siafoundation/types'

type Currency = string
type Signature = string
type Address = string
type Hash256 = string // 32 bytes
type PrivateKey = string
type PublicKey = string // 32 bytes

type AccountToken = {
account: PublicKey
validUntil: string
Expand Down Expand Up @@ -92,7 +91,7 @@ export type RPCWriteSector = {

export type RPC = RPCSettings | RPCReadSector | RPCWriteSector

export type WASM = {
export type WasmApi = {
rhp: {
generateAccount: () => {
privateKey?: PrivateKey
Expand Down Expand Up @@ -189,7 +188,7 @@ export type WASM = {
encodedTransaction?: string
error?: string
}
signTransaction: (
signTransactionV1: (
cs: ConsensusState,
cn: ConsensusNetwork,
txn: Transaction,
Expand Down
8 changes: 4 additions & 4 deletions libs/sdk/src/wallet.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ describe('wallet', () => {
it('signs a valid transaction', async () => {
const sdk = await initSDKTest()
const { privateKey } = sdk.wallet.keyPairFromSeedPhrase(mockPhrase!, 0)
const { error, signature } = sdk.wallet.signTransaction(
const { error, signature } = sdk.wallet.signTransactionV1(
getConsensusState(),
getConsensusNetwork(),
getTransaction(),
Expand All @@ -160,13 +160,13 @@ describe('wallet', () => {
)
expect(error).toBeUndefined()
expect(signature).toEqual(
'sig:c58f8fe1ee5a08147484a53af7d3a64eca8039794b6c475342f0d8927b04d3172b3ed72861c183c73e87d719b782fb291dbfe8b3e0b1088095a9264bc97b6f06'
'xY+P4e5aCBR0hKU699OmTsqAOXlLbEdTQvDYknsE0xcrPtcoYcGDxz6H1xm3gvspHb/os+CxCICVqSZLyXtvBg=='
)
})
it('errors if the signature index is invalid', async () => {
const sdk = await initSDKTest()
const { privateKey } = sdk.wallet.keyPairFromSeedPhrase(mockPhrase!, 0)
const { error, signature } = sdk.wallet.signTransaction(
const { error, signature } = sdk.wallet.signTransactionV1(
getConsensusState(),
getConsensusNetwork(),
getTransaction(),
Expand All @@ -178,7 +178,7 @@ describe('wallet', () => {
})
it('errors if the private key is invalid', async () => {
const sdk = await initSDKTest()
const { error, signature } = sdk.wallet.signTransaction(
const { error, signature } = sdk.wallet.signTransactionV1(
getConsensusState(),
getConsensusNetwork(),
getTransaction(),
Expand Down
2 changes: 1 addition & 1 deletion libs/sdk/src/wasm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ export async function initWASM(): Promise<void> {
try {
const go = new window.Go()
const source = await wasm(go.importObject)
await go.run(source.instance)
go.run(source.instance)
} catch (e) {
throw new Error(`failed to initialize WASM: ${(e as Error).message}`)
}
Expand Down
1 change: 1 addition & 0 deletions libs/types/src/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export type OutputID = string
export type EncryptionKey = string
export type FileContractID = string
export type PublicKey = string
export type PrivateKey = string
export type TransactionID = Hash256
export type SiacoinOutputID = Hash256
export type SiafundOutputID = Hash256
Expand Down
2 changes: 1 addition & 1 deletion sdk/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ func main() {
"addressFromSpendPolicy": jsFunc(addressFromSpendPolicy),
"encodeTransaction": jsFunc(encodeTransaction),
"transactionId": jsFunc(transactionID),
"signTransaction": jsFunc(signTransaction),
"signTransactionV1": jsFunc(signTransactionV1),
},
})
c := make(chan bool, 1)
Expand Down
6 changes: 4 additions & 2 deletions sdk/wallet.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package main
import (
"bytes"
"crypto/ed25519"
"encoding/base64"
"encoding/hex"
"fmt"
"syscall/js"
Expand Down Expand Up @@ -146,7 +147,7 @@ func encodeTransaction(this js.Value, args []js.Value) result {
}

// SignTransaction returns the signature of a transaction.
func signTransaction(this js.Value, args []js.Value) result {
func signTransactionV1(this js.Value, args []js.Value) result {
if err := checkArgs(args, js.TypeObject, js.TypeObject, js.TypeObject, js.TypeNumber, js.TypeString); err != nil {
return resultErr(err)
}
Expand Down Expand Up @@ -187,8 +188,9 @@ func signTransaction(this js.Value, args []js.Value) result {
} else {
sigHash = cs.PartialSigHash(txn, tsig.CoveredFields)
}
sig := privateKey.SignHash(sigHash)
return result(map[string]any{
"signature": privateKey.SignHash(sigHash).String(),
"signature": base64.StdEncoding.EncodeToString(sig[:]),
})
}

Expand Down
Loading

0 comments on commit d26a952

Please sign in to comment.