Skip to content

fix: unsigned submittable #890

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

Merged
merged 9 commits into from
Jul 24, 2024
Merged
Show file tree
Hide file tree
Changes from 2 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
61 changes: 60 additions & 1 deletion packages/sdk-js/src/DidHelpers/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,13 @@

import { Blockchain } from '@kiltprotocol/chain-helpers'
import { multibaseKeyToDidKey } from '@kiltprotocol/did'
import type {
KeyringPair,
KiltAddress,
MultibaseKeyPair,
} from '@kiltprotocol/types'
import { Keyring, Multikey, Crypto } from '@kiltprotocol/utils'
import { TransactionSigner } from 'chain-helpers/src/blockchain/Blockchain.js'

import type {
AcceptedPublicKeyEncodings,
Expand All @@ -24,7 +31,10 @@ export async function submitImpl(
awaitFinalized?: boolean
}
): ReturnType<TransactionHandlers['submit']> {
const submittable = await getSubmittable(options)
const submittable = await getSubmittable({
...options,
signSubmittable: true,
})

const { awaitFinalized = true } = options
const result = await Blockchain.submitSignedTx(
Expand Down Expand Up @@ -63,3 +73,52 @@ export function convertPublicKey(pk: AcceptedPublicKeyEncodings): {
}
return { publicKey, type }
}

export function extractSubmitterSignerAndAccount(
submitter:
| KeyringPair
| Blockchain.TransactionSigner
| MultibaseKeyPair
| KiltAddress
): {
submitterSigner: TransactionSigner | KeyringPair | undefined
submitterAccount: KiltAddress
} {
let submitterSigner: TransactionSigner | KeyringPair | undefined
let submitterAccount: KiltAddress

// KiltAddress
if (typeof submitter === 'string') {
submitterAccount = submitter
}
// KeyringPair
else if ('address' in submitter) {
submitterAccount = submitter.address as KiltAddress
submitterSigner = submitter
}
// Blockchain.TransactionSigner
else if ('id' in submitter) {
submitterAccount = submitter.id as KiltAddress
submitterSigner = submitter
}
// MultibaseKeyPair
else if ('publicKeyMultibase' in submitter) {
submitterAccount = Crypto.encodeAddress(
Multikey.decodeMultibaseKeypair(submitter).publicKey,
38
)
const keypair = Multikey.decodeMultibaseKeypair(submitter)
if (keypair.type === 'x25519') {
throw new Error('x25519 keys are not supported')
}
const keyring = new Keyring().createFromPair(
keypair,
undefined,
keypair.type === 'secp256k1' ? 'ecdsa' : keypair.type
)
submitterSigner = keyring
} else {
throw new Error('type of submitter is invalid')
}
return { submitterSigner, submitterAccount }
}
20 changes: 13 additions & 7 deletions packages/sdk-js/src/DidHelpers/createDid.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,15 @@ import {
type NewDidVerificationKey,
signingMethodTypes,
} from '@kiltprotocol/did'
import type { KiltAddress, SignerInterface } from '@kiltprotocol/types'
import type { SignerInterface } from '@kiltprotocol/types'
import { Crypto, Signers } from '@kiltprotocol/utils'
import { checkResultImpl } from './checkResult.js'

import { convertPublicKey, submitImpl } from './common.js'
import {
convertPublicKey,
extractSubmitterSignerAndAccount,
submitImpl,
} from './common.js'
import type {
AcceptedPublicKeyEncodings,
SharedArguments,
Expand All @@ -43,15 +47,14 @@ export function createDid(
submitOptions = {}
) => {
const { fromPublicKey, submitter, signers, api } = options
const { signSubmittable = true } = submitOptions
const { signSubmittable = false } = submitOptions
const { publicKey, type } = convertPublicKey(fromPublicKey)

if (!signingMethodTypes.includes(type)) {
throw new Error(`unknown key type ${type}`)
}
const submitterAccount = (
'address' in submitter ? submitter.address : submitter.id
) as KiltAddress
const { submitterSigner, submitterAccount } =
extractSubmitterSignerAndAccount(submitter)

const accountSigners = (
await Promise.all(
Expand All @@ -76,7 +79,10 @@ export function createDid(
)

if (signSubmittable) {
didCreation = await Blockchain.signTx(didCreation, submitter)
if (typeof submitterSigner === 'undefined') {
throw new Error('submitter does not include a secret key')
}
didCreation = await Blockchain.signTx(didCreation, submitterSigner)
}

return {
Expand Down
8 changes: 6 additions & 2 deletions packages/sdk-js/src/DidHelpers/interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@
import type { ApiPromise } from '@polkadot/api'
import type { SubmittableResultValue } from '@polkadot/api/types'
import type { GenericEvent } from '@polkadot/types'

import type { Blockchain } from '@kiltprotocol/chain-helpers'
import type {
DidDocument,
HexString,
KeyringPair,
KiltAddress,
MultibaseKeyPair,
MultibasePublicKey,
SignerInterface,
Expand Down Expand Up @@ -101,7 +101,11 @@ export type SharedArguments = {
didDocument: DidDocument
api: ApiPromise
signers: AcceptedSigners[]
submitter: KeyringPair | Blockchain.TransactionSigner
submitter:
| KeyringPair
| Blockchain.TransactionSigner
| MultibaseKeyPair
| KiltAddress
}

type PublicKeyAndType = {
Expand Down
47 changes: 46 additions & 1 deletion packages/sdk-js/src/DidHelpers/transact.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ describe('transact', () => {
expectedEvents: [
{ section: 'attestation', method: 'AttestationCreated' },
],
}).getSubmittable({ signSubmittable: false })
}).getSubmittable()

expect(txHex).toContain('0x')
const parsed = mockedApi.tx(txHex)
Expand Down Expand Up @@ -115,4 +115,49 @@ describe('transact', () => {
value: confirmed.toJSON(),
})
})

it('creates a signed submittable', async () => {
const { txHex } = await transact({
didDocument,
api: mockedApi,
submitter: keypair,
signers: [keypair],
call: mockedApi.tx.attestation.add(
new Uint8Array(32).fill(1),
new Uint8Array(32).fill(1),
null
),
expectedEvents: [
{ section: 'attestation', method: 'AttestationCreated' },
],
}).getSubmittable({ signSubmittable: true })

expect(txHex).toContain('0x')
const parsed = mockedApi.tx(txHex)
expect(parsed.method).toHaveProperty('section', 'did')
expect(parsed.method).toHaveProperty('method', 'submitDidCall')
// todo check signature?
})

it('creates an unsigned submittable', async () => {
const { txHex } = await transact({
didDocument,
api: mockedApi,
submitter: keypair.address,
signers: [keypair],
call: mockedApi.tx.attestation.add(
new Uint8Array(32).fill(1),
new Uint8Array(32).fill(1),
null
),
expectedEvents: [
{ section: 'attestation', method: 'AttestationCreated' },
],
}).getSubmittable({ signSubmittable: false })

expect(txHex).toContain('0x')
const parsed = mockedApi.tx(txHex)
expect(parsed.method).toHaveProperty('section', 'did')
expect(parsed.method).toHaveProperty('method', 'submitDidCall')
})
})
20 changes: 10 additions & 10 deletions packages/sdk-js/src/DidHelpers/transact.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,10 @@
*/

import type { Extrinsic } from '@polkadot/types/interfaces'

import { Blockchain } from '@kiltprotocol/chain-helpers'
import { authorizeTx, signersForDid } from '@kiltprotocol/did'
import type { KiltAddress, SubmittableExtrinsic } from '@kiltprotocol/types'

import { submitImpl } from './common.js'
import type { SubmittableExtrinsic } from '@kiltprotocol/types'
import { extractSubmitterSignerAndAccount, submitImpl } from './common.js'
import type { SharedArguments, TransactionHandlers } from './interfaces.js'
import { checkResultImpl } from './checkResult.js'

Expand All @@ -31,7 +29,7 @@ export function transactInternal(
const getSubmittable: TransactionHandlers['getSubmittable'] = async (
submitOptions:
| {
signSubmittable?: boolean // default: true
signSubmittable?: boolean // default: false
didNonce?: number | BigInt
}
| undefined = {}
Expand All @@ -44,13 +42,12 @@ export function transactInternal(
api,
expectedEvents,
} = options
const { didNonce, signSubmittable = true } = submitOptions
const { didNonce, signSubmittable = false } = submitOptions
const call = await callFactory()
const didSigners = await signersForDid(didDocument, ...signers)

const submitterAccount = (
'address' in submitter ? submitter.address : submitter.id
) as KiltAddress
const { submitterSigner, submitterAccount } =
extractSubmitterSignerAndAccount(submitter)

let authorized: SubmittableExtrinsic = await authorizeTx(
didDocument,
Expand All @@ -65,7 +62,10 @@ export function transactInternal(
)

if (signSubmittable) {
authorized = await Blockchain.signTx(authorized, submitter)
if (typeof submitterSigner === 'undefined') {
throw new Error('submitter does not include a secret key')
}
authorized = await Blockchain.signTx(authorized, submitterSigner)
}

return {
Expand Down
8 changes: 4 additions & 4 deletions packages/types/src/Address.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,10 @@ export type KiltAddress = KiltKeyringPair['address']
declare module '@polkadot/keyring' {
function encodeAddress(
key: HexString | Uint8Array | string,
ss58Format?: Prefix
): string
ss58Format: 38
): KiltAddress
function encodeAddress(
key: HexString | Uint8Array | string,
ss58Format?: 38
): KiltAddress
ss58Format?: Prefix
): string
}
2 changes: 1 addition & 1 deletion tests/integration/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ export const devBob = Crypto.makeKeypairFromUri('//Bob')
export const devCharlie = Crypto.makeKeypairFromUri('//Charlie')

export function addressFromRandom(): KiltAddress {
return encodeAddress(randomAsU8a())
return encodeAddress(randomAsU8a()) as KiltAddress
}

export async function isCtypeOnChain(cType: ICType): Promise<boolean> {
Expand Down
Loading