diff --git a/.changeset/cool-tomatoes-deliver.md b/.changeset/cool-tomatoes-deliver.md new file mode 100644 index 000000000..606f8fe27 --- /dev/null +++ b/.changeset/cool-tomatoes-deliver.md @@ -0,0 +1,5 @@ +--- +'@siafoundation/sdk': minor +--- + +Added v2TransactionInputSigHash and signHash methods to API. diff --git a/.changeset/friendly-houses-matter.md b/.changeset/friendly-houses-matter.md new file mode 100644 index 000000000..0e98c81aa --- /dev/null +++ b/.changeset/friendly-houses-matter.md @@ -0,0 +1,5 @@ +--- +'@siafoundation/types': minor +--- + +Added a Result type. diff --git a/.changeset/tidy-lobsters-float.md b/.changeset/tidy-lobsters-float.md new file mode 100644 index 000000000..22e0bfd70 --- /dev/null +++ b/.changeset/tidy-lobsters-float.md @@ -0,0 +1,5 @@ +--- +'@siafoundation/sdk': minor +--- + +Improved the accuracy of all return types. diff --git a/libs/sdk/src/rhp.spec.ts b/libs/sdk/src/rhp.spec.ts index 1fd718fac..a85653cb4 100644 --- a/libs/sdk/src/rhp.spec.ts +++ b/libs/sdk/src/rhp.spec.ts @@ -14,8 +14,11 @@ describe('rhp', () => { describe('generateAccount', () => { it('works', async () => { const sdk = await initSDKTest() - const { privateKey, account, error } = sdk.rhp.generateAccount() - expect(error).toBeUndefined() + const response = sdk.rhp.generateAccount() + if ('error' in response) { + throw new Error(response.error) + } + const { privateKey, account } = response expect(privateKey).toBeDefined() expect(privateKey?.length).toBeGreaterThan(40) expect(account).toBeDefined() @@ -27,11 +30,16 @@ describe('rhp', () => { it('valid', async () => { const sdk = await initSDKTest() const encode = sdk.rhp.encodeSettingsRequest() - expect(encode.rpc).toBeDefined() - expect(encode.error).not.toBeDefined() - const decode = sdk.rhp.decodeSettingsRequest(encode.rpc!) + if ('error' in encode) { + throw new Error(encode.error) + } + const { rpc } = encode + expect(rpc).toBeDefined() + const decode = sdk.rhp.decodeSettingsRequest(rpc!) + if ('error' in decode) { + throw new Error(decode.error) + } expect(decode.data).toEqual({}) - expect(decode.error).toBeUndefined() }) }) describe('response', () => { @@ -39,12 +47,17 @@ describe('rhp', () => { const sdk = await initSDKTest() const json = getSampleRPCSettingsResponse() const encode = sdk.rhp.encodeSettingsResponse(json) - expect(encode.rpc).toBeDefined() - expect(encode.rpc?.length).toEqual(264) - expect(encode.error).toBeUndefined() - const decode = sdk.rhp.decodeSettingsResponse(encode.rpc!) + if ('error' in encode) { + throw new Error(encode.error) + } + const { rpc } = encode + expect(rpc).toBeDefined() + expect(rpc?.length).toEqual(264) + const decode = sdk.rhp.decodeSettingsResponse(rpc!) + if ('error' in decode) { + throw new Error(decode.error) + } expect(decode.data).toEqual(json) - expect(decode.error).toBeUndefined() }) it('encode error', async () => { const sdk = await initSDKTest() @@ -54,20 +67,29 @@ describe('rhp', () => { }, } as RPCSettingsResponse const encode = sdk.rhp.encodeSettingsResponse(json) - expect(encode.rpc).toBeUndefined() - expect(encode.error).toEqual('address must be 76 characters') + if ('error' in encode) { + expect(encode.error).toEqual('address must be 76 characters') + } else { + throw new Error('expected error') + } }) it('decode error', async () => { const sdk = await initSDKTest() const json = getSampleRPCSettingsResponse() const encode = sdk.rhp.encodeSettingsResponse(json) + if ('error' in encode) { + throw new Error(encode.error) + } // manipulate the valid rpc to make it invalid encode.rpc!.set([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 0) const decode = sdk.rhp.decodeSettingsResponse(encode.rpc!) - expect(decode.data).not.toEqual(json) - expect(decode.error).toEqual( - 'encoded object contains invalid length prefix (723118041428460547 elems > 11254 bytes left in stream)' - ) + if ('error' in decode) { + expect(decode.error).toEqual( + 'encoded object contains invalid length prefix (723118041428460547 elems > 11254 bytes left in stream)' + ) + } else { + throw new Error('expected error') + } }) }) }) @@ -91,11 +113,16 @@ describe('rhp', () => { length: 4, } const encode = sdk.rhp.encodeReadSectorRequest(json) - expect(encode.rpc?.length).toEqual(376) - expect(encode.error).toBeUndefined() - const decode = sdk.rhp.decodeReadSectorRequest(encode.rpc!) + if ('error' in encode) { + throw new Error(encode.error) + } + const { rpc } = encode + expect(rpc?.length).toEqual(376) + const decode = sdk.rhp.decodeReadSectorRequest(rpc!) + if ('error' in decode) { + throw new Error(decode.error) + } expect(decode.data).toEqual(json) - expect(decode.error).toBeUndefined() }) it('encode error', async () => { const sdk = await initSDKTest() @@ -114,10 +141,13 @@ describe('rhp', () => { length: 4, } const encode = sdk.rhp.encodeReadSectorRequest(json) - expect(encode.rpc).toBeUndefined() - expect(encode.error).toEqual( - "decoding acct: failed: encoding/hex: invalid byte: U+0069 'i'" - ) + if ('error' in encode) { + expect(encode.error).toEqual( + "decoding acct: failed: encoding/hex: invalid byte: U+0069 'i'" + ) + } else { + throw new Error('expected error') + } }) }) describe('response', () => { @@ -130,17 +160,22 @@ describe('rhp', () => { dataLength: 4, } const encode = sdk.rhp.encodeReadSectorResponse(json) - expect(encode.rpc?.toString()).toEqual( + if ('error' in encode) { + throw new Error(encode.error) + } + const { rpc } = encode + expect(rpc?.toString()).toEqual( [ 0, 1, 0, 0, 0, 0, 0, 0, 0, 69, 114, 86, 214, 161, 96, 59, 239, 127, 169, 87, 167, 11, 91, 169, 106, 157, 239, 47, 234, 139, 76, 20, 131, 6, 13, 123, 165, 207, 138, 7, 44, 4, 0, 0, 0, 0, 0, 0, 0, ].toString() ) - expect(encode.error).toBeUndefined() - const decode = sdk.rhp.decodeReadSectorResponse(encode.rpc!) + const decode = sdk.rhp.decodeReadSectorResponse(rpc!) + if ('error' in decode) { + throw new Error(decode.error) + } expect(decode.data).toEqual(json) - expect(decode.error).toBeUndefined() }) it('encode error', async () => { const sdk = await initSDKTest() @@ -149,10 +184,13 @@ describe('rhp', () => { dataLength: 4, } const encode = sdk.rhp.encodeReadSectorResponse(json) - expect(encode.rpc).toBeUndefined() - expect(encode.error).toEqual( - 'decoding "invalid" failed: encoding/hex: invalid byte: U+0069 \'i\'' - ) + if ('error' in encode) { + expect(encode.error).toEqual( + 'decoding "invalid" failed: encoding/hex: invalid byte: U+0069 \'i\'' + ) + } else { + throw new Error('expected error') + } }) }) }) @@ -174,11 +212,16 @@ describe('rhp', () => { prices: getSampleHostPrices(), } const encode = sdk.rhp.encodeWriteSectorRequest(json) - expect(encode.rpc?.length).toEqual(336) - expect(encode.error).toBeUndefined() - const decode = sdk.rhp.decodeWriteSectorRequest(encode.rpc!) + if ('error' in encode) { + throw new Error(encode.error) + } + const { rpc } = encode + expect(rpc?.length).toEqual(336) + const decode = sdk.rhp.decodeWriteSectorRequest(rpc!) + if ('error' in decode) { + throw new Error(decode.error) + } expect(decode.data).toEqual(json) - expect(decode.error).toBeUndefined() }) it('encode error', async () => { const sdk = await initSDKTest() @@ -195,10 +238,13 @@ describe('rhp', () => { prices: getSampleHostPrices(), } as RPCWriteSectorRequest const encode = sdk.rhp.encodeWriteSectorRequest(json) - expect(encode.rpc).toBeUndefined() - expect(encode.error).toEqual( - "decoding acct: failed: encoding/hex: invalid byte: U+0069 'i'" - ) + if ('error' in encode) { + expect(encode.error).toEqual( + "decoding acct: failed: encoding/hex: invalid byte: U+0069 'i'" + ) + } else { + throw new Error('expected error') + } }) }) describe('response', () => { @@ -208,17 +254,22 @@ describe('rhp', () => { root: '457256d6a1603bef7fa957a70b5ba96a9def2fea8b4c1483060d7ba5cf8a072c', } const encode = sdk.rhp.encodeWriteSectorResponse(json) - expect(encode.rpc?.toString()).toEqual( + if ('error' in encode) { + throw new Error(encode.error) + } + const { rpc } = encode + expect(rpc?.toString()).toEqual( [ 0, 69, 114, 86, 214, 161, 96, 59, 239, 127, 169, 87, 167, 11, 91, 169, 106, 157, 239, 47, 234, 139, 76, 20, 131, 6, 13, 123, 165, 207, 138, 7, 44, ].toString() ) - expect(encode.error).toBeUndefined() - const decode = sdk.rhp.decodeWriteSectorResponse(encode.rpc!) + const decode = sdk.rhp.decodeWriteSectorResponse(rpc!) + if ('error' in decode) { + throw new Error(decode.error) + } expect(decode.data).toEqual(json) - expect(decode.error).toBeUndefined() }) it('encode error', async () => { const sdk = await initSDKTest() @@ -226,10 +277,13 @@ describe('rhp', () => { root: 'invalid', } as RPCWriteSectorResponse const encode = sdk.rhp.encodeWriteSectorResponse(json) - expect(encode.rpc).toBeUndefined() - expect(encode.error).toEqual( - 'decoding "invalid" failed: encoding/hex: invalid byte: U+0069 \'i\'' - ) + if ('error' in encode) { + expect(encode.error).toEqual( + 'decoding "invalid" failed: encoding/hex: invalid byte: U+0069 \'i\'' + ) + } else { + throw new Error('expected error') + } }) }) }) diff --git a/libs/sdk/src/types.ts b/libs/sdk/src/types.ts index e6486f737..11be2f10a 100644 --- a/libs/sdk/src/types.ts +++ b/libs/sdk/src/types.ts @@ -9,6 +9,8 @@ import { Hash256, PublicKey, PrivateKey, + V2Transaction, + Result, } from '@siafoundation/types' type AccountToken = { @@ -97,114 +99,106 @@ export type RPC = RPCSettings | RPCReadSector | RPCWriteSector export type WasmApi = { rhp: { - generateAccount: () => { - privateKey?: PrivateKey - account?: PublicKey - error?: string - } + generateAccount: () => Result<{ + privateKey: PrivateKey + account: PublicKey + }> // settings - encodeSettingsRequest: (data: RPCSettingsRequest) => { - rpc?: Uint8Array - error?: string - } - decodeSettingsRequest: (rpc: Uint8Array) => { - data?: Record - error?: string - } - encodeSettingsResponse: (data: RPCSettingsResponse) => { - rpc?: Uint8Array - error?: string - } - decodeSettingsResponse: (rpc: Uint8Array) => { - data?: RPCSettingsResponse - error?: string - } + encodeSettingsRequest: (data: RPCSettingsRequest) => Result<{ + rpc: Uint8Array + }> + decodeSettingsRequest: (rpc: Uint8Array) => Result<{ + data: Record + }> + encodeSettingsResponse: (data: RPCSettingsResponse) => Result<{ + rpc: Uint8Array + }> + decodeSettingsResponse: (rpc: Uint8Array) => Result<{ + data: RPCSettingsResponse + }> // read sector - encodeReadSectorRequest: (data: RPCReadSectorRequest) => { - rpc?: Uint8Array - error?: string - } - decodeReadSectorRequest: (rpc: Uint8Array) => { - data?: RPCReadSectorRequest - error?: string - } - encodeReadSectorResponse: (data: RPCReadSectorResponse) => { - rpc?: Uint8Array - error?: string - } - decodeReadSectorResponse: (rpc: Uint8Array) => { - data?: RPCReadSectorResponse - error?: string - } + encodeReadSectorRequest: (data: RPCReadSectorRequest) => Result<{ + rpc: Uint8Array + }> + decodeReadSectorRequest: (rpc: Uint8Array) => Result<{ + data: RPCReadSectorRequest + }> + encodeReadSectorResponse: (data: RPCReadSectorResponse) => Result<{ + rpc: Uint8Array + }> + decodeReadSectorResponse: (rpc: Uint8Array) => Result<{ + data: RPCReadSectorResponse + }> // read sector - encodeWriteSectorRequest: (data: RPCWriteSectorRequest) => { - rpc?: Uint8Array - error?: string - } - decodeWriteSectorRequest: (rpc: Uint8Array) => { - data?: RPCWriteSectorRequest - error?: string - } - encodeWriteSectorResponse: (data: RPCWriteSectorResponse) => { - rpc?: Uint8Array - error?: string - } - decodeWriteSectorResponse: (rpc: Uint8Array) => { - data?: RPCWriteSectorResponse - error?: string - } + encodeWriteSectorRequest: (data: RPCWriteSectorRequest) => Result<{ + rpc: Uint8Array + }> + decodeWriteSectorRequest: (rpc: Uint8Array) => Result<{ + data: RPCWriteSectorRequest + }> + encodeWriteSectorResponse: (data: RPCWriteSectorResponse) => Result<{ + rpc: Uint8Array + }> + decodeWriteSectorResponse: (rpc: Uint8Array) => Result<{ + data: RPCWriteSectorResponse + }> } wallet: { - generateSeedPhrase: () => { - phrase?: string - error?: string - } - generateKeyPair: () => { - privateKey?: string - publicKey?: string - error?: string - } + generateSeedPhrase: () => Result<{ + phrase: string + }> + generateKeyPair: () => Result<{ + privateKey: string + publicKey: string + }> keyPairFromSeedPhrase: ( phrase: string, index: number - ) => { - privateKey?: string - publicKey?: string - error?: string - } - standardUnlockConditions: (publicKey: string) => { - unlockConditions?: UnlockConditions - error?: string - } - standardUnlockHash: (publicKey: string) => { - address?: string - error?: string - } - addressFromUnlockConditions: (unlockConditions: UnlockConditions) => { - address?: string - error?: string - } - addressFromSpendPolicy: (spendPolicy: Record) => { - address?: string - error?: string - } - encodeTransaction: (txn: Transaction) => { - encodedTransaction?: string - error?: string - } + ) => Result<{ + privateKey: string + publicKey: string + }> + standardUnlockConditions: (publicKey: string) => Result<{ + unlockConditions: UnlockConditions + }> + standardUnlockHash: (publicKey: string) => Result<{ + address: string + }> + addressFromUnlockConditions: ( + unlockConditions: UnlockConditions + ) => Result<{ + address: string + }> + addressFromSpendPolicy: (spendPolicy: Record) => Result<{ + address: string + }> + encodeTransaction: (txn: Transaction) => Result<{ + encodedTransaction: string + }> signTransactionV1: ( cs: ConsensusState, cn: ConsensusNetwork, txn: Transaction, sigIndex: number, privateKey: string - ) => { - signature?: string - error?: string - } - transactionId: (txn: Transaction) => { - id?: string - error?: string - } + ) => Result<{ + signature: string + }> + v2TransactionInputSigHash: ( + state: ConsensusState, + network: ConsensusNetwork, + txn: V2Transaction + ) => Result<{ + sigHash: string + }> + signHash: ( + privateKey: string, + hash: string + ) => Result<{ + signature: string + }> + transactionId: (txn: Transaction) => Result<{ + id: string + }> } } diff --git a/libs/types/src/utils.ts b/libs/types/src/utils.ts index 44d529936..84f6fba00 100644 --- a/libs/types/src/utils.ts +++ b/libs/types/src/utils.ts @@ -5,3 +5,9 @@ export type Nullish = T | null | undefined export type NoUndefined = { [K in keyof T]: Exclude } + +export type Result = + | T + | { + error: string + } diff --git a/sdk/wallet.go b/sdk/wallet.go index 3d20d0333..5c60ad52b 100644 --- a/sdk/wallet.go +++ b/sdk/wallet.go @@ -211,9 +211,9 @@ func transactionID(this js.Value, args []js.Value) result { }) } -// v2TransactionInputSigHash returns the input sighash of a v2 transaction. +// v2TransactionInputSigHash returns the input sigHash of a v2 transaction. func v2TransactionInputSigHash(_ js.Value, args []js.Value) result { - if err := checkArgs(args, js.TypeObject, js.TypeObject, js.TypeObject, js.TypeNumber, js.TypeString); err != nil { + if err := checkArgs(args, js.TypeObject, js.TypeObject, js.TypeObject); err != nil { return resultErr(err) } @@ -234,7 +234,7 @@ func v2TransactionInputSigHash(_ js.Value, args []js.Value) result { cs.Network = &cn return result(map[string]any{ - "sighash": cs.InputSigHash(txn).String(), + "sigHash": cs.InputSigHash(txn).String(), }) }