diff --git a/.changeset/fast-suits-punch.md b/.changeset/fast-suits-punch.md
new file mode 100644
index 000000000..453f1c7a2
--- /dev/null
+++ b/.changeset/fast-suits-punch.md
@@ -0,0 +1,5 @@
+---
+'@siafoundation/sdk': minor
+---
+
+signTransaction has been updated to the more specific signTransactionV1.
diff --git a/.changeset/honest-falcons-rhyme.md b/.changeset/honest-falcons-rhyme.md
new file mode 100644
index 000000000..05d559919
--- /dev/null
+++ b/.changeset/honest-falcons-rhyme.md
@@ -0,0 +1,5 @@
+---
+'@siafoundation/sdk': minor
+---
+
+WebTransportClient no longer requires the SDK API as an explicit constructor parameter.
diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml
index f22f3b561..78fd0d3a4 100644
--- a/.github/workflows/pr.yml
+++ b/.github/workflows/pr.yml
@@ -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
diff --git a/.github/workflows/release-main.yml b/.github/workflows/release-main.yml
index 515f12a71..f67caca7b 100644
--- a/.github/workflows/release-main.yml
+++ b/.github/workflows/release-main.yml
@@ -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
diff --git a/apps/walletd-e2e/project.json b/apps/walletd-e2e/project.json
index a7a3ac2f1..25516baa9 100644
--- a/apps/walletd-e2e/project.json
+++ b/apps/walletd-e2e/project.json
@@ -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",
@@ -14,6 +15,5 @@
"lint": {
"executor": "@nx/eslint:lint"
}
- },
- "implicitDependencies": ["walletd"]
+ }
}
diff --git a/apps/walletd/config/providers.tsx b/apps/walletd/config/providers.tsx
index 46c37e9a4..7cec3aced 100644
--- a/apps/walletd/config/providers.tsx
+++ b/apps/walletd/config/providers.tsx
@@ -4,6 +4,7 @@ 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
@@ -11,19 +12,21 @@ type Props = {
export function Providers({ children }: Props) {
return (
-
-
-
-
-
- {/* this is here so that dialogs can use all the other providers,
+
+
+
+
+
+
+ {/* this is here so that dialogs can use all the other providers,
and the other providers can trigger dialogs */}
-
- {children}
-
-
-
-
-
+
+ {children}
+
+
+
+
+
+
)
}
diff --git a/apps/walletd/contexts/app/index.tsx b/apps/walletd/contexts/app/index.tsx
new file mode 100644
index 000000000..a11cd151c
--- /dev/null
+++ b/apps/walletd/contexts/app/index.tsx
@@ -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
+
+const AppContext = createContext({} as State)
+export const useApp = () => useContext(AppContext)
+
+type Props = {
+ children: React.ReactNode
+}
+
+export function AppProvider({ children }: Props) {
+ const state = useAppMain()
+ return {children}
+}
diff --git a/apps/walletd/project.json b/apps/walletd/project.json
index a76a17073..bdf55fcef 100644
--- a/apps/walletd/project.json
+++ b/apps/walletd/project.json
@@ -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",
@@ -67,6 +68,7 @@
"test": {
"executor": "@nx/jest:jest",
"outputs": ["{workspaceRoot}/coverage/apps/walletd"],
+ "dependsOn": ["sdk:build"],
"options": {
"jestConfig": "apps/walletd/jest.config.ts"
}
diff --git a/libs/sdk/project.json b/libs/sdk/project.json
index 838351a47..d0c68e004 100644
--- a/libs/sdk/project.json
+++ b/libs/sdk/project.json
@@ -5,8 +5,7 @@
"projectType": "library",
"tags": [],
"namedInputs": {
- "go": ["{workspaceRoot}/sdk/**/*"],
- "production": ["default", "go"]
+ "go": ["{workspaceRoot}/sdk/**/*"]
},
"targets": {
"compile": {
@@ -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",
diff --git a/libs/sdk/src/index.ts b/libs/sdk/src/index.ts
index e59a87889..cf280db3f 100644
--- a/libs/sdk/src/index.ts
+++ b/libs/sdk/src/index.ts
@@ -1,2 +1,4 @@
-export * from './init'
export * from './types'
+export { initSDK } from './init'
+export { getSDK } from './sdk'
+export type { SDK } from './sdk'
diff --git a/libs/sdk/src/sdk.ts b/libs/sdk/src/sdk.ts
index 948d8a4c6..330af96d7 100644
--- a/libs/sdk/src/sdk.ts
+++ b/libs/sdk/src/sdk.ts
@@ -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,
}
}
diff --git a/libs/sdk/src/transport.ts b/libs/sdk/src/transport.ts
index 372c4e848..c9c1735e5 100644
--- a/libs/sdk/src/transport.ts
+++ b/libs/sdk/src/transport.ts
@@ -1,3 +1,4 @@
+import { getWasmApi } from './sdk'
import {
RPCReadSectorResponse,
RPCSettingsResponse,
@@ -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
@@ -101,8 +103,8 @@ export class WebTransportClient {
): Promise {
return this.sendRequest(
readSector,
- this.#wasm.rhp.encodeReadSectorRequest,
- this.#wasm.rhp.decodeReadSectorResponse
+ getWasmApi().rhp.encodeReadSectorRequest,
+ getWasmApi().rhp.decodeReadSectorResponse
)
}
@@ -111,16 +113,16 @@ export class WebTransportClient {
): Promise {
return this.sendRequest(
writeSector,
- this.#wasm.rhp.encodeWriteSectorRequest,
- this.#wasm.rhp.decodeWriteSectorResponse
+ getWasmApi().rhp.encodeWriteSectorRequest,
+ getWasmApi().rhp.decodeWriteSectorResponse
)
}
async sendRPCSettingsRequest(): Promise {
return this.sendRequest(
undefined,
- this.#wasm.rhp.encodeSettingsRequest,
- this.#wasm.rhp.decodeSettingsResponse
+ getWasmApi().rhp.encodeSettingsRequest,
+ getWasmApi().rhp.decodeSettingsResponse
)
}
}
diff --git a/libs/sdk/src/types.ts b/libs/sdk/src/types.ts
index 8d3458dc4..1008727aa 100644
--- a/libs/sdk/src/types.ts
+++ b/libs/sdk/src/types.ts
@@ -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
@@ -92,7 +91,7 @@ export type RPCWriteSector = {
export type RPC = RPCSettings | RPCReadSector | RPCWriteSector
-export type WASM = {
+export type WasmApi = {
rhp: {
generateAccount: () => {
privateKey?: PrivateKey
@@ -189,7 +188,7 @@ export type WASM = {
encodedTransaction?: string
error?: string
}
- signTransaction: (
+ signTransactionV1: (
cs: ConsensusState,
cn: ConsensusNetwork,
txn: Transaction,
diff --git a/libs/sdk/src/wallet.spec.ts b/libs/sdk/src/wallet.spec.ts
index 01961d8fc..bac4011d2 100644
--- a/libs/sdk/src/wallet.spec.ts
+++ b/libs/sdk/src/wallet.spec.ts
@@ -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(),
@@ -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(),
@@ -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(),
diff --git a/libs/sdk/src/wasm.ts b/libs/sdk/src/wasm.ts
index d257acab8..f004fe447 100644
--- a/libs/sdk/src/wasm.ts
+++ b/libs/sdk/src/wasm.ts
@@ -5,7 +5,7 @@ export async function initWASM(): Promise {
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}`)
}
diff --git a/libs/types/src/core.ts b/libs/types/src/core.ts
index aff0d7e63..3a297a5bb 100644
--- a/libs/types/src/core.ts
+++ b/libs/types/src/core.ts
@@ -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
diff --git a/sdk/main.go b/sdk/main.go
index 8759cce1e..5ebf343d3 100644
--- a/sdk/main.go
+++ b/sdk/main.go
@@ -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)
diff --git a/sdk/wallet.go b/sdk/wallet.go
index 1d9cb04a4..0f9ad4611 100644
--- a/sdk/wallet.go
+++ b/sdk/wallet.go
@@ -3,6 +3,7 @@ package main
import (
"bytes"
"crypto/ed25519"
+ "encoding/base64"
"encoding/hex"
"fmt"
"syscall/js"
@@ -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)
}
@@ -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[:]),
})
}
diff --git a/tsconfig.base.json b/tsconfig.base.json
index c6790e54e..c944ddae6 100644
--- a/tsconfig.base.json
+++ b/tsconfig.base.json
@@ -27,7 +27,9 @@
"libs/react-sia-central/src/index.ts"
],
"@siafoundation/react-walletd": ["libs/react-walletd/src/index.ts"],
- "@siafoundation/sdk": ["dist/libs/sdk"],
+ // "buildLibsFromSource": false does not work with the next executor
+ // this is a very annoying workaround
+ "@siafoundation/sdk": ["dist/libs/sdk/index.esm.js"],
"@siafoundation/sia-central": ["libs/sia-central/src/index.ts"],
"@siafoundation/types": ["libs/types/src/index.ts"],
"@siafoundation/units": ["libs/units/src/index.ts"]