Skip to content

Commit 03cc0c2

Browse files
authored
Merge pull request #7286 from BitGo/COIN-6128
feat(sdk-coin-canton): added verify transaction method handling for wallet init
2 parents 0da7eaa + b7f600b commit 03cc0c2

File tree

6 files changed

+91
-9
lines changed

6 files changed

+91
-9
lines changed

modules/sdk-coin-canton/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
node_modules/
22
.idea/
33
dist/
4+
.DS_Store

modules/sdk-coin-canton/src/canton.ts

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,13 @@ import {
1010
ParseTransactionOptions,
1111
SignedTransaction,
1212
SignTransactionOptions,
13-
VerifyAddressOptions,
13+
TransactionType,
14+
TssVerifyAddressOptions,
1415
VerifyTransactionOptions,
1516
} from '@bitgo/sdk-core';
1617
import { auditEddsaPrivateKey } from '@bitgo/sdk-lib-mpc';
17-
import { BaseCoin as StaticsBaseCoin } from '@bitgo/statics';
18+
import { BaseCoin as StaticsBaseCoin, coins } from '@bitgo/statics';
19+
import { TransactionBuilderFactory } from './lib';
1820
import { KeyPair as CantonKeyPair } from './lib/keyPair';
1921
import utils from './lib/utils';
2022

@@ -70,12 +72,29 @@ export class Canton extends BaseCoin {
7072
}
7173

7274
/** @inheritDoc */
73-
verifyTransaction(params: VerifyTransactionOptions): Promise<boolean> {
74-
throw new Error('Method not implemented.');
75+
async verifyTransaction(params: VerifyTransactionOptions): Promise<boolean> {
76+
const coinConfig = coins.get(this.getChain());
77+
// extract `txParams` when verifying other transaction types
78+
const { txPrebuild: txPrebuild } = params;
79+
const rawTx = txPrebuild.txHex;
80+
if (!rawTx) {
81+
throw new Error('missing required tx prebuild property txHex');
82+
}
83+
const txBuilder = new TransactionBuilderFactory(coinConfig).from(rawTx);
84+
const transaction = txBuilder.transaction;
85+
switch (transaction.type) {
86+
case TransactionType.WalletInitialization: {
87+
// there is no input for this type of transaction, so always return true
88+
return true;
89+
}
90+
default: {
91+
throw new Error(`unknown transaction type, ${transaction.type}`);
92+
}
93+
}
7594
}
7695

7796
/** @inheritDoc */
78-
isWalletAddress(params: VerifyAddressOptions): Promise<boolean> {
97+
isWalletAddress(params: TssVerifyAddressOptions): Promise<boolean> {
7998
throw new Error('Method not implemented.');
8099
}
81100

@@ -104,7 +123,9 @@ export class Canton extends BaseCoin {
104123

105124
/** @inheritDoc */
106125
isValidAddress(address: string): boolean {
107-
throw new Error('Method not implemented.');
126+
// canton addresses are of the form, partyHint::fingerprint
127+
// where partyHint is of length 5 and fingerprint is 68 characters long
128+
return utils.isValidAddress(address);
108129
}
109130

110131
/** @inheritDoc */

modules/sdk-coin-canton/src/lib/transactionBuilder.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ export abstract class TransactionBuilder extends BaseTransactionBuilder {
2727
protected abstract get transactionType(): TransactionType;
2828

2929
/** @inheritdoc */
30-
protected get transaction(): Transaction {
30+
get transaction(): Transaction {
3131
return this._transaction;
3232
}
3333

modules/sdk-coin-canton/src/lib/utils.ts

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,10 @@ import { RecordField } from './resourcesInterface';
1212
export class Utils implements BaseUtils {
1313
/** @inheritdoc */
1414
isValidAddress(address: string): boolean {
15-
throw new Error('Method not implemented.');
15+
if (!address || address.trim() === '') return false;
16+
const [partyHint, fingerprint] = address.trim().split('::');
17+
if (!partyHint || !fingerprint) return false;
18+
return partyHint.length === 5 && this.isValidCantonHex(fingerprint);
1619
}
1720

1821
/** @inheritdoc */
@@ -40,6 +43,16 @@ export class Utils implements BaseUtils {
4043
throw new Error('Method not implemented.');
4144
}
4245

46+
/**
47+
* Method to validate the input is a valid canton hex string
48+
* @param {String} value the hex string value
49+
* @returns {Boolean} true if valid
50+
*/
51+
isValidCantonHex(value: string): boolean {
52+
const regex = /^[a-fA-F0-9]{68}$/;
53+
return regex.test(value);
54+
}
55+
4356
/**
4457
* Method to create fingerprint (part of the canton partyId) from public key
4558
* @param {String} publicKey the public key

modules/sdk-coin-canton/test/resources.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,3 +59,13 @@ export const InvalidOneStepPreApprovalPrepareResponse = {
5959
hashingSchemeVersion: 'HASHING_SCHEME_VERSION_V2',
6060
hashingDetails: null,
6161
};
62+
63+
export const CANTON_ADDRESSES = {
64+
VALID_ADDRESS: '12205::12205b4e3537a95126d90604592344d8ad3c3ddccda4f79901954280ee19c576714d',
65+
// party hint is not 5 characters
66+
INVALID_PARTY_HINT: '123456::12205b4e3537a95126d90604592344d8ad3c3ddccda4f79901954280ee19c576714d',
67+
// fingerprint is not a valid hex value
68+
INVALID_FINGERPRINT: '12205::12205b4e3537a95126d9060459234gd8ad3c3ddccda4f79901954280ee19c576714d',
69+
MISSING_PARTY_HINT: '::12205b4e3537a95126d9060459234gd8ad3c3ddccda4f79901954280ee19c576714d',
70+
MISSING_FINGERPRINT: '12205::',
71+
};

modules/sdk-coin-canton/test/unit/utils.ts

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
11
import assert from 'assert';
22
import should from 'should';
33
import utils from '../../src/lib/utils';
4-
import { GenerateTopologyResponse, PreparedTransactionRawData, PrepareSubmissionResponse } from '../resources';
4+
import {
5+
CANTON_ADDRESSES,
6+
GenerateTopologyResponse,
7+
PreparedTransactionRawData,
8+
PrepareSubmissionResponse,
9+
} from '../resources';
510

611
describe('Canton Util', function () {
712
describe('Raw transaction parser', function () {
@@ -31,4 +36,36 @@ describe('Canton Util', function () {
3136
assert.strictEqual(computedHash, PrepareSubmissionResponse.preparedTransactionHash);
3237
});
3338
});
39+
40+
describe('Check if the address is valid', function () {
41+
it('should return true when the address is valid', function () {
42+
const isValid = utils.isValidAddress(CANTON_ADDRESSES.VALID_ADDRESS);
43+
should.exist(isValid);
44+
assert.strictEqual(isValid, true);
45+
});
46+
47+
it('should return false when party hint is invalid', function () {
48+
const isValid = utils.isValidAddress(CANTON_ADDRESSES.INVALID_PARTY_HINT);
49+
should.exist(isValid);
50+
assert.strictEqual(isValid, false);
51+
});
52+
53+
it('should return false when fingerprint is invalid', function () {
54+
const isValid = utils.isValidAddress(CANTON_ADDRESSES.INVALID_FINGERPRINT);
55+
should.exist(isValid);
56+
assert.strictEqual(isValid, false);
57+
});
58+
59+
it('should return false when party hint is missing', function () {
60+
const isValid = utils.isValidAddress(CANTON_ADDRESSES.MISSING_PARTY_HINT);
61+
should.exist(isValid);
62+
assert.strictEqual(isValid, false);
63+
});
64+
65+
it('should return false when fingerprint is missing', function () {
66+
const isValid = utils.isValidAddress(CANTON_ADDRESSES.MISSING_FINGERPRINT);
67+
should.exist(isValid);
68+
assert.strictEqual(isValid, false);
69+
});
70+
});
3471
});

0 commit comments

Comments
 (0)