Skip to content

Commit f70489c

Browse files
authored
ethereum: added e2e tests (#2218)
# Goal The goal of this PR is <!-- insert goal here --> Closes #2203 # Discussion - added e2e tests for more usecase for ethereum keys - Some clean up and refactoring - Added eslint rules to enforce correct usage # Checklist - [X] e2e Tests added?
1 parent 0c34adc commit f70489c

19 files changed

+765
-109
lines changed

e2e/capacity/capacityFail.test.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import {
1919
assertAddNewKey,
2020
} from '../scaffolding/helpers';
2121
import { getFundingSource } from '../scaffolding/funding';
22+
import { getUnifiedPublicKey } from '../scaffolding/ethereum';
2223

2324
const FUNDS_AMOUNT: bigint = 50n * DOLLARS;
2425
const fundingSource = getFundingSource('capacity-transactions-fail');
@@ -111,7 +112,7 @@ describe('Capacity Transaction Failures', function () {
111112

112113
// As current owner, add a new set of control keys that do not have a balance.
113114
const newControlKeypair = createKeys('NewKeyNoBalance');
114-
const newPublicKey = newControlKeypair.publicKey;
115+
const newPublicKey = getUnifiedPublicKey(newControlKeypair);
115116
const addKeyPayload: AddKeyData = await generateAddKeyPayload({
116117
msaId: capacityProvider,
117118
newPublicKey: newPublicKey,
@@ -193,7 +194,7 @@ describe('Capacity Transaction Failures', function () {
193194
// Add new key
194195
const newKeyPayload: AddKeyData = await generateAddKeyPayload({
195196
msaId: new u64(ExtrinsicHelper.api.registry, capacityProvider),
196-
newPublicKey: noTokensKeys.publicKey,
197+
newPublicKey: getUnifiedPublicKey(noTokensKeys),
197198
});
198199
const addKeyData = ExtrinsicHelper.api.registry.createType('PalletMsaAddKeyData', newKeyPayload);
199200

e2e/capacity/capacity_rpc.test.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import {
1313
} from '../scaffolding/helpers';
1414
import { FeeDetails } from '@polkadot/types/interfaces';
1515
import { getFundingSource } from '../scaffolding/funding';
16+
import { getUnifiedPublicKey } from '../scaffolding/ethereum';
1617

1718
const FUNDS_AMOUNT: bigint = 50n * DOLLARS;
1819
const fundingSource = getFundingSource('capacity-rpcs');
@@ -46,7 +47,7 @@ describe('Capacity RPC', function () {
4647
const addProviderData = ExtrinsicHelper.api.registry.createType('PalletMsaAddProvider', addProviderPayload);
4748
const delegatorKeys = createKeys('delegatorKeys');
4849
const call = ExtrinsicHelper.api.tx.msa.createSponsoredAccountWithDelegation(
49-
delegatorKeys.publicKey,
50+
getUnifiedPublicKey(delegatorKeys),
5051
signPayloadSr25519(delegatorKeys, addProviderData),
5152
addProviderPayload
5253
);
@@ -89,7 +90,7 @@ describe('Capacity RPC', function () {
8990
const addProviderData = ExtrinsicHelper.api.registry.createType('PalletMsaAddProvider', addProviderPayload);
9091
const delegatorKeys = createKeys('delegatorKeys');
9192
const insideTx = ExtrinsicHelper.api.tx.msa.createSponsoredAccountWithDelegation(
92-
delegatorKeys.publicKey,
93+
getUnifiedPublicKey(delegatorKeys),
9394
signPayloadSr25519(delegatorKeys, addProviderData),
9495
addProviderPayload
9596
);

e2e/capacity/transactions.test.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ import {
3838
} from '../scaffolding/helpers';
3939
import { ipfsCid } from '../messages/ipfs';
4040
import { getFundingSource } from '../scaffolding/funding';
41+
import { getUnifiedPublicKey } from '../scaffolding/ethereum';
4142

4243
const FUNDS_AMOUNT: bigint = 50n * DOLLARS;
4344
const fundingSource = getFundingSource('capacity-transactions');
@@ -92,7 +93,7 @@ describe('Capacity Transactions', function () {
9293

9394
authorizedKeys.push(await createAndFundKeypair(fundingSource, 50_000_000n));
9495
defaultPayload.msaId = capacityProvider;
95-
defaultPayload.newPublicKey = authorizedKeys[0].publicKey;
96+
defaultPayload.newPublicKey = getUnifiedPublicKey(authorizedKeys[0]);
9697

9798
const payload = await generateAddKeyPayload(defaultPayload);
9899
const addKeyData = ExtrinsicHelper.api.registry.createType('PalletMsaAddKeyData', payload);

e2e/capacity/transactionsBatch.test.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import {
1616
getTestHandle,
1717
} from '../scaffolding/helpers';
1818
import { getFundingSource } from '../scaffolding/funding';
19+
import { getUnifiedPublicKey } from '../scaffolding/ethereum';
1920

2021
const FUNDS_AMOUNT: bigint = 50n * DOLLARS;
2122
const fundingSource = getFundingSource('capacity-transactions-batch');
@@ -49,7 +50,7 @@ describe('Capacity Transactions Batch', function () {
4950
const addProviderData = ExtrinsicHelper.api.registry.createType('PalletMsaAddProvider', addProviderPayload);
5051
const delegatorKeys = createKeys('delegatorKeys');
5152
const createSponsoredAccountWithDelegation = ExtrinsicHelper.api.tx.msa.createSponsoredAccountWithDelegation(
52-
delegatorKeys.publicKey,
53+
getUnifiedPublicKey(delegatorKeys),
5354
signPayloadSr25519(delegatorKeys, addProviderData),
5455
addProviderPayload
5556
);
@@ -70,7 +71,7 @@ describe('Capacity Transactions Batch', function () {
7071
};
7172

7273
const claimHandle = ExtrinsicHelper.api.tx.handles.claimHandle(
73-
delegatorKeys.publicKey,
74+
getUnifiedPublicKey(delegatorKeys),
7475
claimHandleProof,
7576
claimHandlePayload
7677
);
@@ -95,7 +96,7 @@ describe('Capacity Transactions Batch', function () {
9596
const addProviderData = ExtrinsicHelper.api.registry.createType('PalletMsaAddProvider', addProviderPayload);
9697
const delegatorKeys = createKeys('delegatorKeys');
9798
const createSponsoredAccountWithDelegation = ExtrinsicHelper.api.tx.msa.createSponsoredAccountWithDelegation(
98-
delegatorKeys.publicKey,
99+
getUnifiedPublicKey(delegatorKeys),
99100
signPayloadSr25519(delegatorKeys, addProviderData),
100101
addProviderPayload
101102
);
@@ -116,7 +117,7 @@ describe('Capacity Transactions Batch', function () {
116117
};
117118

118119
const claimHandle = ExtrinsicHelper.api.tx.handles.claimHandle(
119-
delegatorKeys.publicKey,
120+
getUnifiedPublicKey(delegatorKeys),
120121
calimHandleProof,
121122
claimHandlePayload
122123
);

e2e/eslint.config.mjs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,19 @@ export default tseslint.config(
5151
},
5252
],
5353
'allow-namespace': 'off',
54+
'no-restricted-syntax': [
55+
'error',
56+
{
57+
message:
58+
'Direct usage of keyPair.address is not allowed in this file. please use getUnifiedAddress function.',
59+
selector: 'MemberExpression[property.name="address"]',
60+
},
61+
{
62+
message:
63+
'Direct usage of keyPair.publicKey is not allowed in this file. please use getUnifiedPublicKey function',
64+
selector: 'MemberExpression[property.name="publicKey"]',
65+
},
66+
],
5467
},
5568
}
5669
);

e2e/load-tests/signatureRegistry.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import { KeyringPair } from '@polkadot/keyring/types';
1313
import { AddKeyData, ExtrinsicHelper } from '../scaffolding/extrinsicHelpers';
1414
import { u64, Option } from '@polkadot/types';
1515
import { getFundingSource } from '../scaffolding/funding';
16-
import { getUnifiedAddress } from '../scaffolding/ethereum';
16+
import { getUnifiedAddress, getUnifiedPublicKey } from '../scaffolding/ethereum';
1717

1818
interface GeneratedMsa {
1919
id: u64;
@@ -154,7 +154,7 @@ async function addSigs(msaId: u64, keys: KeyringPair, blockNumber: number, nonce
154154

155155
const defaultPayload: AddKeyData = {};
156156
defaultPayload.msaId = msaId;
157-
defaultPayload.newPublicKey = newKeys.publicKey;
157+
defaultPayload.newPublicKey = getUnifiedPublicKey(newKeys);
158158
const payload = await generateAddKeyPayload(defaultPayload, 100, blockNumber);
159159

160160
const addKeyData = ExtrinsicHelper.api.registry.createType('PalletMsaAddKeyData', payload);
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
import '@frequency-chain/api-augment';
2+
import assert from 'assert';
3+
import { DOLLARS, createAndFundKeypair, createKeys } from '../scaffolding/helpers';
4+
import { KeyringPair } from '@polkadot/keyring/types';
5+
import { Extrinsic, ExtrinsicHelper } from '../scaffolding/extrinsicHelpers';
6+
import { getFundingSource } from '../scaffolding/funding';
7+
import { getUnifiedAddress } from '../scaffolding/ethereum';
8+
9+
const fundingSource: KeyringPair = getFundingSource('frequency-balance-ethereum');
10+
11+
describe('Balance transfer ethereum', function () {
12+
describe('setup', function () {
13+
let senderSr25519Keys: KeyringPair;
14+
let senderEthereumKeys: KeyringPair;
15+
let ethereumKeys: KeyringPair;
16+
let ethereumKeys2: KeyringPair;
17+
let sr25519Keys: KeyringPair;
18+
19+
before(async function () {
20+
senderSr25519Keys = await createAndFundKeypair(fundingSource, 30n * DOLLARS);
21+
senderEthereumKeys = await createAndFundKeypair(fundingSource, 30n * DOLLARS, undefined, undefined, 'ethereum');
22+
ethereumKeys = await createKeys('another-key-1', 'ethereum');
23+
ethereumKeys2 = await createKeys('another-key-2', 'ethereum');
24+
sr25519Keys = await createKeys('another-sr25519', 'sr25519');
25+
});
26+
27+
it('should transfer from sr25519 to ethereum style key', async function () {
28+
const transferAmount = 10n * DOLLARS;
29+
const extrinsic = new Extrinsic(
30+
() => ExtrinsicHelper.api.tx.balances.transferKeepAlive(getUnifiedAddress(ethereumKeys), transferAmount),
31+
senderSr25519Keys,
32+
ExtrinsicHelper.api.events.balances.Transfer
33+
);
34+
const { target } = await extrinsic.signAndSend();
35+
assert.notEqual(target, undefined, 'should have returned Transfer event');
36+
const accountInfo = await ExtrinsicHelper.getAccountInfo(ethereumKeys);
37+
assert(accountInfo.data.free.toBigInt() >= transferAmount);
38+
});
39+
40+
it('should transfer from sr25519 to ethereum 20 byte address', async function () {
41+
const transferAmount = 10n * DOLLARS;
42+
const extrinsic = new Extrinsic(
43+
// this is using MultiAddress::Address20 type in Rust since addressRaw is 20 bytes ethereum address
44+
() => ExtrinsicHelper.api.tx.balances.transferKeepAlive(ethereumKeys2.addressRaw, transferAmount),
45+
senderSr25519Keys,
46+
ExtrinsicHelper.api.events.balances.Transfer
47+
);
48+
const { target } = await extrinsic.signAndSend();
49+
assert.notEqual(target, undefined, 'should have returned Transfer event');
50+
const accountInfo = await ExtrinsicHelper.getAccountInfo(ethereumKeys2);
51+
assert(accountInfo.data.free.toBigInt() >= transferAmount);
52+
});
53+
54+
it('should transfer from an ethereum key to sr25519 key', async function () {
55+
const transferAmount = 10n * DOLLARS;
56+
const extrinsic = new Extrinsic(
57+
() => ExtrinsicHelper.api.tx.balances.transferKeepAlive(getUnifiedAddress(sr25519Keys), transferAmount),
58+
senderEthereumKeys,
59+
ExtrinsicHelper.api.events.balances.Transfer
60+
);
61+
const { target } = await extrinsic.signAndSend();
62+
assert.notEqual(target, undefined, 'should have returned Transfer event');
63+
const accountInfo = await ExtrinsicHelper.getAccountInfo(sr25519Keys);
64+
assert(accountInfo.data.free.toBigInt() >= transferAmount);
65+
});
66+
});
67+
});

e2e/miscellaneous/frequency.test.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { Extrinsic, ExtrinsicHelper } from '../scaffolding/extrinsicHelpers';
66
import { getFundingSource } from '../scaffolding/funding';
77
import { u8, Option } from '@polkadot/types';
88
import { u8aToHex } from '@polkadot/util/u8a/toHex';
9-
import { getUnifiedAddress } from '../scaffolding/ethereum';
9+
import { getUnifiedAddress, getUnifiedPublicKey } from '../scaffolding/ethereum';
1010

1111
const fundingSource: KeyringPair = getFundingSource('frequency-misc');
1212

@@ -23,7 +23,7 @@ describe('Frequency', function () {
2323
it('Get events successfully', async function () {
2424
const balance_pallet = new u8(ExtrinsicHelper.api.registry, 10);
2525
const transfer_event = new u8(ExtrinsicHelper.api.registry, 2);
26-
const dest_account = u8aToHex(keypairB.publicKey).slice(2);
26+
const dest_account = u8aToHex(getUnifiedPublicKey(keypairB)).slice(2);
2727
const beforeBlockNumber = await getBlockNumber();
2828

2929
const extrinsic = new Extrinsic(
@@ -66,7 +66,7 @@ describe('Frequency', function () {
6666
}
6767
// wait a little for all of the above transactions to get queued
6868
await new Promise((resolve) => setTimeout(resolve, 1000));
69-
const missingNonce = await ExtrinsicHelper.getMissingNonceValues(keypairB.publicKey);
69+
const missingNonce = await ExtrinsicHelper.getMissingNonceValues(getUnifiedPublicKey(keypairB));
7070
assert.equal(missingNonce.length, 4, 'Could not get missing nonce values');
7171

7272
// applying the missing nonce values to next transactions to unblock the stuck ones
Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
import '@frequency-chain/api-augment';
2+
import assert from 'assert';
3+
import {
4+
createKeys,
5+
createAndFundKeypair,
6+
generateAddKeyPayload,
7+
CENTS,
8+
signPayload,
9+
MultiSignatureType,
10+
} from '../scaffolding/helpers';
11+
import { KeyringPair } from '@polkadot/keyring/types';
12+
import { AddKeyData, ExtrinsicHelper } from '../scaffolding/extrinsicHelpers';
13+
import { u64 } from '@polkadot/types';
14+
import { Codec } from '@polkadot/types/types';
15+
import { getFundingSource } from '../scaffolding/funding';
16+
import { getUnifiedPublicKey } from '../scaffolding/ethereum';
17+
18+
const maxU64 = 18_446_744_073_709_551_615n;
19+
const fundingSource = getFundingSource('msa-key-management-ethereum');
20+
21+
describe('MSA Key management Ethereum', function () {
22+
describe('addPublicKeyToMsa Ethereum', function () {
23+
let keys: KeyringPair;
24+
let msaId: u64;
25+
let secondaryKey: KeyringPair;
26+
const defaultPayload: AddKeyData = {};
27+
let payload: AddKeyData;
28+
let ownerSig: MultiSignatureType;
29+
let newSig: MultiSignatureType;
30+
let badSig: MultiSignatureType;
31+
let addKeyData: Codec;
32+
33+
before(async function () {
34+
// Setup an MSA with one key and a secondary funded key
35+
keys = await createAndFundKeypair(fundingSource, 5n * CENTS, undefined, undefined, 'ethereum');
36+
const { target } = await ExtrinsicHelper.createMsa(keys).signAndSend();
37+
assert.notEqual(target?.data.msaId, undefined, 'MSA Id not in expected event');
38+
msaId = target!.data.msaId;
39+
40+
secondaryKey = await createAndFundKeypair(fundingSource, 5n * CENTS, undefined, undefined, 'ethereum');
41+
42+
// Default payload making it easier to test `addPublicKeyToMsa`
43+
defaultPayload.msaId = msaId;
44+
defaultPayload.newPublicKey = getUnifiedPublicKey(secondaryKey);
45+
});
46+
47+
beforeEach(async function () {
48+
payload = await generateAddKeyPayload(defaultPayload);
49+
});
50+
51+
it('should fail to add public key if origin is not one of the signers of the payload (MsaOwnershipInvalidSignature) for a Ethereum key', async function () {
52+
const badKeys: KeyringPair = createKeys();
53+
addKeyData = ExtrinsicHelper.api.registry.createType('PalletMsaAddKeyData', payload);
54+
newSig = signPayload(secondaryKey, addKeyData);
55+
badSig = signPayload(badKeys, addKeyData);
56+
const op = ExtrinsicHelper.addPublicKeyToMsa(keys, badSig, newSig, payload);
57+
await assert.rejects(op.fundAndSend(fundingSource), {
58+
name: 'MsaOwnershipInvalidSignature',
59+
});
60+
});
61+
62+
it('should fail to add public key if origin does not own MSA (NotMsaOwner) for a Ethereum key', async function () {
63+
const newPayload = await generateAddKeyPayload({
64+
...defaultPayload,
65+
msaId: new u64(ExtrinsicHelper.api.registry, maxU64),
66+
});
67+
addKeyData = ExtrinsicHelper.api.registry.createType('PalletMsaAddKeyData', newPayload);
68+
ownerSig = signPayload(keys, addKeyData);
69+
newSig = signPayload(secondaryKey, addKeyData);
70+
const op = ExtrinsicHelper.addPublicKeyToMsa(keys, ownerSig, newSig, newPayload);
71+
await assert.rejects(op.fundAndSend(fundingSource), {
72+
name: 'NotMsaOwner',
73+
});
74+
});
75+
76+
it('should successfully add a new public key to an existing MSA & disallow duplicate signed payload submission (SignatureAlreadySubmitted) for a Ethereum key', async function () {
77+
addKeyData = ExtrinsicHelper.api.registry.createType('PalletMsaAddKeyData', payload);
78+
79+
ownerSig = signPayload(keys, addKeyData);
80+
newSig = signPayload(secondaryKey, addKeyData);
81+
const addPublicKeyOp = ExtrinsicHelper.addPublicKeyToMsa(keys, ownerSig, newSig, payload);
82+
83+
const { target: publicKeyEvents } = await addPublicKeyOp.fundAndSend(fundingSource);
84+
85+
assert.notEqual(publicKeyEvents, undefined, 'should have added public key');
86+
87+
await assert.rejects(
88+
addPublicKeyOp.fundAndSend(fundingSource),
89+
'should reject sending the same signed payload twice'
90+
);
91+
});
92+
93+
it('should fail if attempting to add the same key more than once (KeyAlreadyRegistered) for a Ethereum key', async function () {
94+
const addKeyData = ExtrinsicHelper.api.registry.createType('PalletMsaAddKeyData', payload);
95+
96+
const ownerSig = signPayload(keys, addKeyData);
97+
const newSig = signPayload(secondaryKey, addKeyData);
98+
const addPublicKeyOp = ExtrinsicHelper.addPublicKeyToMsa(keys, ownerSig, newSig, payload);
99+
100+
await assert.rejects(addPublicKeyOp.fundAndSend(fundingSource), {
101+
name: 'KeyAlreadyRegistered',
102+
});
103+
});
104+
105+
it('should allow new keypair to act for/on MSA for a Ethereum key', async function () {
106+
const thirdKey = createKeys();
107+
const newPayload = await generateAddKeyPayload({
108+
...defaultPayload,
109+
newPublicKey: getUnifiedPublicKey(thirdKey),
110+
});
111+
addKeyData = ExtrinsicHelper.api.registry.createType('PalletMsaAddKeyData', newPayload);
112+
ownerSig = signPayload(secondaryKey, addKeyData);
113+
newSig = signPayload(thirdKey, addKeyData);
114+
const op = ExtrinsicHelper.addPublicKeyToMsa(secondaryKey, ownerSig, newSig, newPayload);
115+
const { target: event } = await op.fundAndSend(fundingSource);
116+
assert.notEqual(event, undefined, 'should have added public key');
117+
118+
// Cleanup
119+
await assert.doesNotReject(ExtrinsicHelper.deletePublicKey(keys, getUnifiedPublicKey(thirdKey)).signAndSend());
120+
});
121+
});
122+
});

0 commit comments

Comments
 (0)