Skip to content

Commit

Permalink
adds rpc to fetch identity for multisig account (#5715)
Browse files Browse the repository at this point in the history
* adds rpc to fetch identity for multisig account

adds 'wallet/multisig/getAccountIdentity' to retrieve the multisig identity for
an account

endpoint throws an error if the account is not a multisig account or if it is a
coordinator account and doesn't have an identity

differs from 'wallet/multisig/getAccountIdenitities', which returns all
identities for all participants in the multisig

* removes errant import
  • Loading branch information
hughy authored Jan 27, 2025
1 parent 0f0d71f commit acd4c8b
Show file tree
Hide file tree
Showing 5 changed files with 200 additions and 0 deletions.
11 changes: 11 additions & 0 deletions ironfish/src/rpc/clients/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@ import type {
FollowChainStreamResponse,
GetAccountIdentitiesRequest,
GetAccountIdentitiesResponse,
GetAccountIdentityRequest,
GetAccountIdentityResponse,
GetAccountNotesStreamRequest,
GetAccountNotesStreamResponse,
GetAccountsRequest,
Expand Down Expand Up @@ -313,6 +315,15 @@ export abstract class RpcClient {
).waitForEnd()
},

getAccountIdentity: (
params: GetAccountIdentityRequest,
): Promise<RpcResponseEnded<GetAccountIdentityResponse>> => {
return this.request<GetAccountIdentityResponse>(
`${ApiNamespace.wallet}/multisig/getAccountIdentity`,
params,
).waitForEnd()
},

dkg: {
round1: (params: DkgRound1Request): Promise<RpcResponseEnded<DkgRound1Response>> => {
return this.request<DkgRound1Response>(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
{
"Route multisig/getAccountIdentity throws an error if the account is not a multisig account": [
{
"value": {
"encrypted": false,
"version": 4,
"id": "7481f108-9a5f-442b-9281-383084698d23",
"name": "test",
"spendingKey": "f9b5b5e38073cf7429dff092832748e39a38e82736f6107ae80f1f6a3a20f1f0",
"viewKey": "945f43341b4b2ce2c18c48b146222bda226de0301db715b398f1285b552914941e732c78e4cb4296213bd71d85e75cf3142968d42e0dfdae0d2e4293a505f849",
"incomingViewKey": "5a102178f7479d00d4a5ae7e4c067e9e1e57fb2cc9a039cf92e4e6b43098a905",
"outgoingViewKey": "52b6c3b9716133406a5292585d34c8fb4f64e3f051662c7db76f4bd35681e922",
"publicAddress": "ec93a7a17f2991a3638804711c527eee8bec696d9fce1de7bb55e3c035cfbd6a",
"createdAt": {
"sequence": 1,
"hash": {
"type": "Buffer",
"data": "base64:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA="
}
},
"scanningEnabled": true,
"proofAuthorizingKey": "e738313bc11134cc4821ee7f8bd1dab37129f60c577c981421ee8099ace29801"
},
"head": {
"hash": {
"type": "Buffer",
"data": "base64:R5HXrp+X3xAO8VWOhHctagm0N2I4goP3XG8goyqIqoY="
},
"sequence": 1
}
}
]
}
95 changes: 95 additions & 0 deletions ironfish/src/rpc/routes/wallet/multisig/getAccountIdentity.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
import { useAccountFixture } from '../../../../testUtilities'
import { createRouteTest } from '../../../../testUtilities/routeTest'
import { ACCOUNT_SCHEMA_VERSION, AccountImport, JsonEncoder } from '../../../../wallet'

describe('Route multisig/getAccountIdentity', () => {
const routeTest = createRouteTest()

it('returns the identity belonging to an account', async () => {
const identity1 = await routeTest.client.wallet.multisig.createParticipant({
name: 'identity1',
})
const identity2 = await routeTest.client.wallet.multisig.createParticipant({
name: 'identity2',
})

const participants = [
{ identity: identity1.content.identity },
{ identity: identity2.content.identity },
]

const request = { minSigners: 2, participants }
const response = await routeTest.client.wallet.multisig.createTrustedDealerKeyPackage(
request,
)

const importAccount = await routeTest.client.wallet.importAccount({
account: response.content.participantAccounts[0].account,
})

const accountName = importAccount.content.name

const accountIdentity = await routeTest.client.wallet.multisig.getAccountIdentity({
account: accountName,
})

expect(accountIdentity.content.identity).toEqual(participants[0].identity)
})

it('throws an error for a coordinator account', async () => {
const identity1 = await routeTest.client.wallet.multisig.createParticipant({
name: 'identity1',
})
const identity2 = await routeTest.client.wallet.multisig.createParticipant({
name: 'identity2',
})

const participants = [
{ identity: identity1.content.identity },
{ identity: identity2.content.identity },
]

const request = { minSigners: 2, participants }
const response = await routeTest.client.wallet.multisig.createTrustedDealerKeyPackage(
request,
)

const account: AccountImport = {
name: 'coordinator',
version: ACCOUNT_SCHEMA_VERSION,
createdAt: null,
spendingKey: null,
viewKey: response.content.viewKey,
incomingViewKey: response.content.incomingViewKey,
outgoingViewKey: response.content.outgoingViewKey,
publicAddress: response.content.publicAddress,
proofAuthorizingKey: response.content.proofAuthorizingKey,
multisigKeys: {
publicKeyPackage: response.content.publicKeyPackage,
},
}

await routeTest.client.wallet.importAccount({
account: new JsonEncoder().encode(account),
})

await expect(
routeTest.client.wallet.multisig.getAccountIdentity({
account: 'coordinator',
}),
).rejects.toThrow('does not have a multisig identity')
})

it('throws an error if the account is not a multisig account', async () => {
const account = await useAccountFixture(routeTest.wallet)

await expect(
routeTest.client.wallet.multisig.getAccountIdentity({
account: account.name,
}),
).rejects.toThrow('is not a multisig account')
})
})
60 changes: 60 additions & 0 deletions ironfish/src/rpc/routes/wallet/multisig/getAccountIdentity.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
import * as yup from 'yup'
import { Assert } from '../../../../assert'
import { WithRequired } from '../../../../utils'
import { Account, AssertMultisig } from '../../../../wallet'
import {
MultisigHardwareSigner,
MultisigSigner,
} from '../../../../wallet/interfaces/multisigKeys'
import { ApiNamespace } from '../../namespaces'
import { routes } from '../../router'
import { AssertHasRpcContext } from '../../rpcContext'
import { getAccount } from '../utils'

export type GetAccountIdentityRequest = {
account?: string
}

export type GetAccountIdentityResponse = {
identity: string
}
export const GetAccountIdentityRequestSchema: yup.ObjectSchema<GetAccountIdentityRequest> = yup
.object({
account: yup.string().optional(),
})
.defined()

export const GetAccountIdentityResponseSchema: yup.ObjectSchema<GetAccountIdentityResponse> =
yup
.object({
identity: yup.string().defined(),
})
.defined()

routes.register<typeof GetAccountIdentityRequestSchema, GetAccountIdentityResponse>(
`${ApiNamespace.wallet}/multisig/getAccountIdentity`,
GetAccountIdentityRequestSchema,
(request, context): void => {
AssertHasRpcContext(request, context, 'wallet')

const account = getAccount(context.wallet, request.data.account)
AssertMultisigOwner(account)

request.end({ identity: account.multisigKeys.identity })
},
)

type MultisigOwnerAccount = WithRequired<Account, 'multisigKeys'> & {
multisigKeys: MultisigSigner | MultisigHardwareSigner
}

function AssertMultisigOwner(account: Account): asserts account is MultisigOwnerAccount {
AssertMultisig(account)
Assert.isTrue(
'identity' in account.multisigKeys,
`Account '${account.name}' does not have a multisig identity`,
)
}
1 change: 1 addition & 0 deletions ironfish/src/rpc/routes/wallet/multisig/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,6 @@ export * from './createParticipant'
export * from './getIdentity'
export * from './getIdentities'
export * from './getAccountIdentities'
export * from './getAccountIdentity'
export * from './importParticipant'
export * from './dkg'

0 comments on commit acd4c8b

Please sign in to comment.