Skip to content

Commit aac249b

Browse files
committed
feat: 🎸 allow multiSig signers to submit proposals
When a multiSig signer submits a transaction it will be wrapped and a `proposal` field will be present in the response (or `multiSig` field present will be in offline payloads)
1 parent 50d1e0d commit aac249b

File tree

60 files changed

+463
-182
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

60 files changed

+463
-182
lines changed

‎README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,10 @@ Process modes include:
129129
- `offline` This creates an unsigned transaction and returns a serialized JSON payload. The information can be signed, and then submitted to the chain.
130130
- `AMQP` This creates an transaction to be processed by worker processes using an AMQP broker to ensure reliable processing
131131

132+
### MultiSig
133+
134+
If the signer of a transaction is a MultiSig signer the transaction will be implicitly wrapped as a MultiSigProposal. This mostly behaves as a normal transaction with a few exceptions. The transaction may need additional approvals depending on the MultiSig configuration, and will be scheduled to run in a later block. The filed `proposal` will be set and additional details will not be set, e.g. `POST /portfolios/create` will not return portfolio information for a MultiSig signer. For offline payloads the field `multiSig` will be set to the acting MultiSig address when a proposal is being made.
135+
132136
### Signing Managers
133137

134138
A signing manager is required for `submit` and `submitWithCallback` processing modes.

‎package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@
4949
"@polymeshassociation/fireblocks-signing-manager": "^2.5.0",
5050
"@polymeshassociation/hashicorp-vault-signing-manager": "^3.4.0",
5151
"@polymeshassociation/local-signing-manager": "^3.3.0",
52-
"@polymeshassociation/polymesh-sdk": "24.7.0-alpha.2",
52+
"@polymeshassociation/polymesh-sdk": "24.7.0-alpha.11",
5353
"@polymeshassociation/signing-manager-types": "^3.2.0",
5454
"class-transformer": "0.5.1",
5555
"class-validator": "^0.14.0",

‎src/accounts/accounts.controller.spec.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ import { IdentityModel } from '~/identities/models/identity.model';
2323
import { IdentitySignerModel } from '~/identities/models/identity-signer.model';
2424
import { NetworkService } from '~/network/network.service';
2525
import { SubsidyService } from '~/subsidy/subsidy.service';
26-
import { extrinsic, testValues } from '~/test-utils/consts';
26+
import { extrinsic, processedTxResult, testValues } from '~/test-utils/consts';
2727
import {
2828
createMockResponseObject,
2929
createMockSubsidy,
@@ -111,7 +111,7 @@ describe('AccountsController', () => {
111111

112112
const result = await controller.transferPolyx(body);
113113

114-
expect(result).toEqual(txResult);
114+
expect(result).toEqual(processedTxResult);
115115
});
116116
});
117117

@@ -229,7 +229,7 @@ describe('AccountsController', () => {
229229

230230
const result = await controller.freezeSecondaryAccounts(body);
231231

232-
expect(result).toEqual(txResult);
232+
expect(result).toEqual(processedTxResult);
233233
});
234234
});
235235

@@ -242,7 +242,7 @@ describe('AccountsController', () => {
242242

243243
const result = await controller.unfreezeSecondaryAccounts(body);
244244

245-
expect(result).toEqual(txResult);
245+
expect(result).toEqual(processedTxResult);
246246
});
247247
});
248248

@@ -257,7 +257,7 @@ describe('AccountsController', () => {
257257

258258
const result = await controller.revokePermissions(body);
259259

260-
expect(result).toEqual(txResult);
260+
expect(result).toEqual(processedTxResult);
261261
});
262262
});
263263

@@ -281,7 +281,7 @@ describe('AccountsController', () => {
281281

282282
const result = await controller.modifyPermissions(body);
283283

284-
expect(result).toEqual(txResult);
284+
expect(result).toEqual(processedTxResult);
285285
});
286286
});
287287

‎src/accounts/accounts.controller.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ import { AccountDetailsModel } from '~/accounts/models/account-details.model';
3232
import { MultiSigDetailsModel } from '~/accounts/models/multi-sig-details.model';
3333
import { PermissionsModel } from '~/accounts/models/permissions.model';
3434
import { BalanceModel } from '~/assets/models/balance.model';
35-
import { ApiArrayResponse, ApiTransactionResponse } from '~/common/decorators/swagger';
35+
import { ApiArrayResponse, ApiTransactionResponse } from '~/common/decorators/';
3636
import { TransactionBaseDto } from '~/common/dto/transaction-base-dto';
3737
import { ExtrinsicModel } from '~/common/models/extrinsic.model';
3838
import { PaginatedResultsModel } from '~/common/models/paginated-results.model';

‎src/assets/assets.controller.spec.ts

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import { createAuthorizationRequestModel } from '~/authorizations/authorizations
1414
import { PaginatedResultsModel } from '~/common/models/paginated-results.model';
1515
import { MetadataService } from '~/metadata/metadata.service';
1616
import { PortfolioDto } from '~/portfolios/dto/portfolio.dto';
17-
import { testValues } from '~/test-utils/consts';
17+
import { processedTxResult, testValues } from '~/test-utils/consts';
1818
import { MockAsset, MockAuthorizationRequest } from '~/test-utils/mocks';
1919
import { MockAssetService, mockMetadataServiceProvider } from '~/test-utils/service-mocks';
2020

@@ -223,7 +223,7 @@ describe('AssetsController', () => {
223223
mockAssetsService.setDocuments.mockResolvedValue(txResult);
224224

225225
const result = await controller.setDocuments({ ticker }, body);
226-
expect(result).toEqual(txResult);
226+
expect(result).toEqual(processedTxResult);
227227
expect(mockAssetsService.setDocuments).toHaveBeenCalledWith(ticker, body);
228228
});
229229
});
@@ -240,7 +240,7 @@ describe('AssetsController', () => {
240240
mockAssetsService.createAsset.mockResolvedValue(txResult);
241241

242242
const result = await controller.createAsset(input);
243-
expect(result).toEqual(txResult);
243+
expect(result).toEqual(processedTxResult);
244244
expect(mockAssetsService.createAsset).toHaveBeenCalledWith(input);
245245
});
246246
});
@@ -252,7 +252,7 @@ describe('AssetsController', () => {
252252
mockAssetsService.issue.mockResolvedValue(txResult);
253253

254254
const result = await controller.issue({ ticker }, { signer, amount });
255-
expect(result).toEqual(txResult);
255+
expect(result).toEqual(processedTxResult);
256256
expect(mockAssetsService.issue).toHaveBeenCalledWith(ticker, { signer, amount });
257257
});
258258
});
@@ -272,7 +272,7 @@ describe('AssetsController', () => {
272272
const result = await controller.transferOwnership({ ticker }, body);
273273

274274
expect(result).toEqual({
275-
...txResult,
275+
...processedTxResult,
276276
// eslint-disable-next-line @typescript-eslint/no-explicit-any
277277
authorizationRequest: createAuthorizationRequestModel(mockAuthorization as any),
278278
});
@@ -288,7 +288,7 @@ describe('AssetsController', () => {
288288
mockAssetsService.redeem.mockResolvedValue(txResult);
289289

290290
const result = await controller.redeem({ ticker }, { signer, amount, from });
291-
expect(result).toEqual(txResult);
291+
expect(result).toEqual(processedTxResult);
292292
expect(mockAssetsService.redeem).toHaveBeenCalledWith(ticker, { signer, amount, from });
293293
});
294294
});
@@ -299,7 +299,7 @@ describe('AssetsController', () => {
299299
mockAssetsService.freeze.mockResolvedValue(txResult);
300300

301301
const result = await controller.freeze({ ticker }, { signer });
302-
expect(result).toEqual(txResult);
302+
expect(result).toEqual(processedTxResult);
303303
expect(mockAssetsService.freeze).toHaveBeenCalledWith(ticker, { signer });
304304
});
305305
});
@@ -310,7 +310,7 @@ describe('AssetsController', () => {
310310
mockAssetsService.unfreeze.mockResolvedValue(txResult);
311311

312312
const result = await controller.unfreeze({ ticker }, { signer });
313-
expect(result).toEqual(txResult);
313+
expect(result).toEqual(processedTxResult);
314314
expect(mockAssetsService.unfreeze).toHaveBeenCalledWith(ticker, { signer });
315315
});
316316
});
@@ -325,7 +325,7 @@ describe('AssetsController', () => {
325325

326326
const result = await controller.controllerTransfer({ ticker }, { signer, origin, amount });
327327

328-
expect(result).toEqual(txResult);
328+
expect(result).toEqual(processedTxResult);
329329
expect(mockAssetsService.controllerTransfer).toHaveBeenCalledWith(ticker, {
330330
signer,
331331
origin,
@@ -391,7 +391,7 @@ describe('AssetsController', () => {
391391

392392
const result = await controller.addRequiredMediators({ ticker }, { signer, mediators });
393393

394-
expect(result).toEqual(txResult);
394+
expect(result).toEqual(processedTxResult);
395395
expect(mockAssetsService.addRequiredMediators).toHaveBeenCalledWith(ticker, {
396396
signer,
397397
mediators,
@@ -408,7 +408,7 @@ describe('AssetsController', () => {
408408

409409
const result = await controller.removeRequiredMediators({ ticker }, { signer, mediators });
410410

411-
expect(result).toEqual(txResult);
411+
expect(result).toEqual(processedTxResult);
412412
expect(mockAssetsService.removeRequiredMediators).toHaveBeenCalledWith(ticker, {
413413
signer,
414414
mediators,
@@ -424,7 +424,7 @@ describe('AssetsController', () => {
424424

425425
const result = await controller.preApprove({ ticker }, { signer });
426426

427-
expect(result).toEqual(txResult);
427+
expect(result).toEqual(processedTxResult);
428428
expect(mockAssetsService.preApprove).toHaveBeenCalledWith(ticker, {
429429
signer,
430430
});
@@ -439,7 +439,7 @@ describe('AssetsController', () => {
439439

440440
const result = await controller.removePreApproval({ ticker }, { signer });
441441

442-
expect(result).toEqual(txResult);
442+
expect(result).toEqual(processedTxResult);
443443
expect(mockAssetsService.removePreApproval).toHaveBeenCalledWith(ticker, {
444444
signer,
445445
});

‎src/assets/assets.controller.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ import { IdentityBalanceModel } from '~/assets/models/identity-balance.model';
2727
import { RequiredMediatorsModel } from '~/assets/models/required-mediators.model';
2828
import { authorizationRequestResolver } from '~/authorizations/authorizations.util';
2929
import { CreatedAuthorizationRequestModel } from '~/authorizations/models/created-authorization-request.model';
30-
import { ApiArrayResponse, ApiTransactionResponse } from '~/common/decorators/swagger';
30+
import { ApiArrayResponse, ApiTransactionResponse } from '~/common/decorators/';
3131
import { PaginatedParamsDto } from '~/common/dto/paginated-params.dto';
3232
import { TransactionBaseDto } from '~/common/dto/transaction-base-dto';
3333
import { TransferOwnershipDto } from '~/common/dto/transfer-ownership.dto';

‎src/authorizations/authorizations.controller.spec.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { BigNumber } from '@polymeshassociation/polymesh-sdk';
33

44
import { AuthorizationsController } from '~/authorizations/authorizations.controller';
55
import { AuthorizationsService } from '~/authorizations/authorizations.service';
6-
import { testValues } from '~/test-utils/consts';
6+
import { processedTxResult, testValues } from '~/test-utils/consts';
77
import { MockAuthorizationsService } from '~/test-utils/service-mocks';
88

99
describe('AuthorizationsController', () => {
@@ -34,7 +34,7 @@ describe('AuthorizationsController', () => {
3434
const authId = new BigNumber(1);
3535
const result = await controller.accept({ id: authId }, { signer });
3636

37-
expect(result).toEqual(txResult);
37+
expect(result).toEqual(processedTxResult);
3838
expect(mockAuthorizationsService.accept).toHaveBeenCalledWith(authId, { signer });
3939
});
4040
});
@@ -46,7 +46,7 @@ describe('AuthorizationsController', () => {
4646
const authId = new BigNumber(1);
4747
const result = await controller.remove({ id: authId }, { signer });
4848

49-
expect(result).toEqual(txResult);
49+
expect(result).toEqual(processedTxResult);
5050
expect(mockAuthorizationsService.remove).toHaveBeenCalledWith(authId, { signer });
5151
});
5252
});

‎src/authorizations/models/created-authorization-request.model.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
/* istanbul ignore file */
22

3-
import { ApiProperty } from '@nestjs/swagger';
3+
import { ApiPropertyOptional } from '@nestjs/swagger';
44
import { Type } from 'class-transformer';
55

66
import { AuthorizationRequestModel } from '~/authorizations/models/authorization-request.model';
77
import { TransactionQueueModel } from '~/common/models/transaction-queue.model';
88

99
export class CreatedAuthorizationRequestModel extends TransactionQueueModel {
10-
@ApiProperty({
10+
@ApiPropertyOptional({
1111
description: 'Details of the newly created Authorization Request',
1212
type: AuthorizationRequestModel,
1313
})

‎src/checkpoints/checkpoints.controller.spec.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import { PeriodComplexityModel } from '~/checkpoints/models/period-complexity.mo
1010
import { ScheduleComplexityModel } from '~/checkpoints/models/schedule-complexity.model';
1111
import { PaginatedResultsModel } from '~/common/models/paginated-results.model';
1212
import { ResultsModel } from '~/common/models/results.model';
13-
import { testValues } from '~/test-utils/consts';
13+
import { processedTxResult, testValues } from '~/test-utils/consts';
1414
import { MockCheckpoint, MockCheckpointSchedule } from '~/test-utils/mocks';
1515
import { MockCheckpointsService } from '~/test-utils/service-mocks';
1616

@@ -115,7 +115,7 @@ describe('CheckpointsController', () => {
115115
const result = await controller.createCheckpoint({ ticker }, body);
116116

117117
expect(result).toEqual({
118-
...txResult,
118+
...processedTxResult,
119119
checkpoint: mockCheckpoint,
120120
});
121121
});
@@ -222,7 +222,7 @@ describe('CheckpointsController', () => {
222222
pendingPoints: [mockDate],
223223
});
224224
expect(result).toEqual({
225-
...txResult,
225+
...processedTxResult,
226226
schedule: mockCreatedSchedule,
227227
});
228228
});
@@ -299,7 +299,7 @@ describe('CheckpointsController', () => {
299299

300300
const result = await controller.deleteSchedule({ id: new BigNumber(1), ticker }, { signer });
301301

302-
expect(result).toEqual(txResult);
302+
expect(result).toEqual(processedTxResult);
303303
});
304304
});
305305

‎src/checkpoints/checkpoints.controller.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ import { CreatedCheckpointModel } from '~/checkpoints/models/created-checkpoint.
2424
import { CreatedCheckpointScheduleModel } from '~/checkpoints/models/created-checkpoint-schedule.model';
2525
import { PeriodComplexityModel } from '~/checkpoints/models/period-complexity.model';
2626
import { ScheduleComplexityModel } from '~/checkpoints/models/schedule-complexity.model';
27-
import { ApiArrayResponse, ApiTransactionResponse } from '~/common/decorators/swagger';
27+
import { ApiArrayResponse, ApiTransactionResponse } from '~/common/decorators/';
2828
import { IsTicker } from '~/common/decorators/validation';
2929
import { IdParamsDto } from '~/common/dto/id-params.dto';
3030
import { PaginatedParamsDto } from '~/common/dto/paginated-params.dto';

‎src/checkpoints/models/created-checkpoint-schedule.model.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
/* istanbul ignore file */
22

3-
import { ApiProperty } from '@nestjs/swagger';
3+
import { ApiPropertyOptional } from '@nestjs/swagger';
44
import { Type } from 'class-transformer';
55

66
import { CheckpointScheduleModel } from '~/checkpoints/models/checkpoint-schedule.model';
77
import { TransactionQueueModel } from '~/common/models/transaction-queue.model';
88

99
export class CreatedCheckpointScheduleModel extends TransactionQueueModel {
10-
@ApiProperty({
10+
@ApiPropertyOptional({
1111
description: 'Static data (and identifiers) of the newly created Schedule',
1212
type: CheckpointScheduleModel,
1313
})

‎src/checkpoints/models/created-checkpoint.model.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
/* istanbul ignore file */
22

3-
import { ApiProperty } from '@nestjs/swagger';
3+
import { ApiPropertyOptional } from '@nestjs/swagger';
44
import { Checkpoint } from '@polymeshassociation/polymesh-sdk/types';
55

66
import { FromEntity } from '~/common/decorators/transformation';
77
import { TransactionQueueModel } from '~/common/models/transaction-queue.model';
88

99
export class CreatedCheckpointModel extends TransactionQueueModel {
10-
@ApiProperty({
10+
@ApiPropertyOptional({
1111
description: 'Identifiers of the newly created Checkpoint',
1212
example: {
1313
id: '1',

‎src/claims/claims.controller.spec.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import { CustomClaimTypeModel } from '~/claims/models/custom-claim-type.model';
1212
import { CustomClaimTypeWithDid } from '~/claims/models/custom-claim-type-did.model';
1313
import { PaginatedResultsModel } from '~/common/models/paginated-results.model';
1414
import { mockPolymeshLoggerProvider } from '~/logger/mock-polymesh-logger';
15-
import { testValues } from '~/test-utils/consts';
15+
import { processedTxResult, testValues } from '~/test-utils/consts';
1616
import { mockClaimsServiceProvider } from '~/test-utils/service-mocks';
1717

1818
const { did, txResult, signer } = testValues;
@@ -55,7 +55,7 @@ describe('ClaimsController', () => {
5555

5656
expect(mockClaimsService.addClaimsOnDid).toHaveBeenCalledWith(mockPayload);
5757

58-
expect(result).toEqual({ ...txResult, results: undefined });
58+
expect(result).toEqual({ ...processedTxResult, results: undefined });
5959
});
6060
});
6161

@@ -67,7 +67,7 @@ describe('ClaimsController', () => {
6767

6868
expect(mockClaimsService.editClaimsOnDid).toHaveBeenCalledWith(mockPayload);
6969

70-
expect(result).toEqual({ ...txResult, results: undefined });
70+
expect(result).toEqual({ ...processedTxResult, results: undefined });
7171
});
7272
});
7373

@@ -79,7 +79,7 @@ describe('ClaimsController', () => {
7979

8080
expect(mockClaimsService.revokeClaimsFromDid).toHaveBeenCalledWith(mockPayload);
8181

82-
expect(result).toEqual({ ...txResult, results: undefined });
82+
expect(result).toEqual({ ...processedTxResult, results: undefined });
8383
});
8484
});
8585

@@ -101,7 +101,7 @@ describe('ClaimsController', () => {
101101
expect(mockClaimsService.registerCustomClaimType).toHaveBeenCalledWith(
102102
mockRegisterCustomClaimTypeDto
103103
);
104-
expect(result).toEqual({ ...txResult, results: undefined });
104+
expect(result).toEqual({ ...processedTxResult, results: undefined });
105105
});
106106
});
107107

‎src/claims/claims.controller.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import { ModifyClaimsDto } from '~/claims/dto/modify-claims.dto';
2020
import { RegisterCustomClaimTypeDto } from '~/claims/dto/register-custom-claim-type.dto';
2121
import { CustomClaimTypeModel } from '~/claims/models/custom-claim-type.model';
2222
import { CustomClaimTypeWithDid } from '~/claims/models/custom-claim-type-did.model';
23-
import { ApiTransactionFailedResponse, ApiTransactionResponse } from '~/common/decorators/swagger';
23+
import { ApiTransactionFailedResponse, ApiTransactionResponse } from '~/common/decorators/';
2424
import { PaginatedResultsModel } from '~/common/models/paginated-results.model';
2525
import { TransactionQueueModel } from '~/common/models/transaction-queue.model';
2626
import { handleServiceResult, TransactionResponseModel } from '~/common/utils';

0 commit comments

Comments
 (0)