Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SDK cleanup, set up SDK in walletd #562

Merged
merged 1 commit into from
Apr 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading