Skip to content

Commit e46f15d

Browse files
authored
feat: added custom opt-in distribution (#1)
1 parent 367a974 commit e46f15d

File tree

86 files changed

+284
-8841
lines changed

Some content is hidden

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

86 files changed

+284
-8841
lines changed

package-lock.json

Lines changed: 15 additions & 8701 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/model/NetworkFile.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
*/
1616

1717
import { ConfigAccount, CustomPreset } from 'symbol-bootstrap';
18+
import { CurrencyDistribution } from 'symbol-bootstrap/lib/model/ConfigPreset';
1819
import { NodeInformation, NodeMetadataType, RestProtocol } from './NodeInformation';
1920

2021
export interface CosignerAccountInput {
@@ -63,7 +64,7 @@ export interface BasicNetworkFile {
6364
isNewNetwork: boolean;
6465
nemesisSeedFolder?: string;
6566
faucetBalances?: number[];
66-
67+
additionalCurrencyDistributions?: CurrencyDistribution[][];
6768
multisig?: {
6869
ownershipCount: number;
6970
cosigners: CosignerPerson[];

src/services/NetworkGenesisService.ts

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ export class NetworkGenesisService {
138138
nemesisBalances.push({
139139
mosaicIndex: mosaicIndex,
140140
address: mainAccount.address.plain(),
141-
amount: parseInt(nodeBalance + NetworkUtils.zeroPad(0, divisibility)),
141+
amount: nodeBalance * 10 ** divisibility,
142142
});
143143
}
144144
});
@@ -213,7 +213,27 @@ export class NetworkGenesisService {
213213
nemesisBalances.push({
214214
mosaicIndex: mosaicIndex,
215215
address: faucetAccount.address.plain(),
216-
amount: parseInt(faucetBalance + NetworkUtils.zeroPad(0, divisibility)),
216+
amount: faucetBalance * 10 ** divisibility,
217+
});
218+
}
219+
});
220+
}
221+
222+
const additionalCurrencyDistributions = input.additionalCurrencyDistributions;
223+
if (additionalCurrencyDistributions) {
224+
nemesisPreset.mosaics.forEach((m, mosaicIndex) => {
225+
const mosaicAdditionalCurrencyDistributions = additionalCurrencyDistributions[mosaicIndex];
226+
if (mosaicAdditionalCurrencyDistributions) {
227+
const divisibility = nemesisPreset.mosaics[mosaicIndex].divisibility;
228+
if (divisibility == undefined) {
229+
throw new Error('Divisibility should be defined!!');
230+
}
231+
mosaicAdditionalCurrencyDistributions.forEach((distribution) => {
232+
nemesisBalances.push({
233+
mosaicIndex: mosaicIndex,
234+
address: distribution.address,
235+
amount: distribution.amount * 10 ** divisibility,
236+
});
217237
});
218238
}
219239
});

src/utils/InitService.ts

Lines changed: 65 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import {
2121
CommandUtils,
2222
ConfigLoader,
2323
CustomPreset,
24+
DeepPartial,
2425
FileSystemService,
2526
Logger,
2627
LoggerFactory,
@@ -29,7 +30,8 @@ import {
2930
Preset,
3031
YamlUtils,
3132
} from 'symbol-bootstrap';
32-
import { Account, NetworkType } from 'symbol-sdk';
33+
import { CurrencyDistribution, MosaicPreset } from 'symbol-bootstrap/lib/model/ConfigPreset';
34+
import { Account, Address, NetworkType } from 'symbol-sdk';
3335
import {
3436
Network,
3537
NetworkConfigurationService,
@@ -97,6 +99,7 @@ export class InitService {
9799
if (!nemesisPreset) throw new Error('Network nemesis must be found!');
98100
if (!nemesisPreset.mosaics) throw new Error(`Network nemesis's mosaics must be found!`);
99101
let faucetBalances: number[] | undefined;
102+
let additionalCurrencyDistributions: CurrencyDistribution[][] | undefined;
100103
let customNetworkPreset: CustomPreset | undefined = {};
101104
if (isNewNetwork) {
102105
customNetworkPreset = _.merge({ nemesis: { mosaics: [] } }, this.params.additionalNetworkPreset);
@@ -126,17 +129,18 @@ export class InitService {
126129
'Enter the basename for the network aliases',
127130
networkPreset.baseNamespace,
128131
);
129-
132+
additionalCurrencyDistributions = [];
130133
for (const [index, mosaic] of nemesisPreset.mosaics.entries()) {
131134
const currencyType = index == 0 ? 'Network' : index == 1 ? 'Harvest' : 'Custom';
132135
const name = await this.promptName(
133136
`${currencyType} Currency Name`,
134137
`Enter the alias for the ${currencyType} Currency`,
135138
mosaic.name,
136139
);
137-
customNetworkPreset.nemesis!.mosaics!.push({
140+
const mosaicPreset: DeepPartial<MosaicPreset> = {
138141
name,
139-
});
142+
};
143+
customNetworkPreset.nemesis!.mosaics!.push(mosaicPreset);
140144
}
141145

142146
const nemesisSignerAccount = await this.promptPrivateKey(networkType, 'Nemesis Signer Account');
@@ -148,15 +152,20 @@ export class InitService {
148152
if (await this.confirm('Do you want to have a Faucet account?')) {
149153
const faucetAccount = await this.promptPrivateKey(networkType, 'Faucet Account');
150154
await keyStore.saveNetworkAccount(networkType, 'faucet', faucetAccount.privateKey);
151-
for (const mosaic of nemesisPreset.mosaics) {
155+
for (const [index, mosaic] of nemesisPreset.mosaics.entries()) {
156+
const name = customNetworkPreset.nemesis!.mosaics![index]?.name || mosaic.name;
152157
const balance = await this.promptNumber(
153158
'Balance',
154-
`What's the initial ${mosaic.name} balance for the Faucet Account ${faucetAccount.address.plain()}?`,
159+
`What's the initial ${name} coin balance for the Faucet Account ${faucetAccount.address.plain()}?`,
155160
Math.floor(mosaic.supply / 100 / Math.pow(10, mosaic.divisibility)) * 5,
156161
);
157162
faucetBalances.push(balance);
158163
}
159164
}
165+
for (const [index, mosaic] of nemesisPreset.mosaics.entries()) {
166+
const name = customNetworkPreset.nemesis!.mosaics![index]?.name || mosaic.name;
167+
additionalCurrencyDistributions.push(await this.promptDistribution(networkType, name));
168+
}
160169

161170
const harvestNetworkFeeSinkAccount = await this.promptPrivateKey(networkType, 'Harvest Network Fee Sink Account');
162171
await keyStore.saveNetworkAccount(networkType, 'harvestNetworkFeeSink', harvestNetworkFeeSinkAccount.privateKey);
@@ -194,6 +203,7 @@ export class InitService {
194203
networkType: networkType!,
195204
isNewNetwork: isNewNetwork,
196205
faucetBalances: faucetBalances,
206+
additionalCurrencyDistributions: additionalCurrencyDistributions,
197207
nemesisSeedFolder: nemesisSeedFolder,
198208
nodeTypes: nodeTypes,
199209
customNetworkPreset: customNetworkPreset,
@@ -283,7 +293,7 @@ export class InitService {
283293
]);
284294
nemesisSeedFolder = nemesisSeedFolderResponse.value;
285295
try {
286-
await new FileSystemService(this.logger).validateSeedFolder(nemesisSeedFolder, '');
296+
new FileSystemService(this.logger).validateSeedFolder(nemesisSeedFolder, '');
287297
} catch (e) {
288298
console.log();
289299
console.log(
@@ -452,6 +462,54 @@ export class InitService {
452462
);
453463
}
454464

465+
public async promptAddress(networkType: NetworkType, fieldName: string): Promise<Address> {
466+
return this.confirmedPrompt<Address>(
467+
fieldName,
468+
async (currentValue): Promise<Address> => {
469+
const { value } = await prompt([
470+
{
471+
name: 'value',
472+
message: `Enter a valid Symbol ${fieldName}`,
473+
type: 'input',
474+
default: currentValue?.plain(),
475+
validate: (value) => {
476+
try {
477+
const address = Address.createFromRawAddress(value);
478+
if (address.networkType != networkType) {
479+
return `it's not for the right network`;
480+
}
481+
return true;
482+
} catch (e) {
483+
return `it is not a valid address. ${NetworkUtils.getMessage(e)}`;
484+
}
485+
},
486+
},
487+
]);
488+
return Address.createFromRawAddress(value);
489+
},
490+
undefined,
491+
(address) => `address ${address.plain()} `,
492+
);
493+
}
494+
495+
public async promptDistribution(networkType: NetworkType, mosaicName: string): Promise<CurrencyDistribution[]> {
496+
const list: CurrencyDistribution[] = [];
497+
console.log();
498+
console.log(
499+
`In additions to the node, faucet and founder accounts, you can include (opt-in) more accounts into the nemesis block by distributing ${mosaicName} coins.`,
500+
);
501+
while (await this.confirm(`Do you want to distribute coin ${mosaicName} to different accounts on the nemesis block?`, false)) {
502+
const address = await this.promptAddress(networkType, 'distribution address');
503+
const amount = await this.promptNumber(
504+
'distribution amount',
505+
`Enter how much ${mosaicName} you want to give to address ${address.plain()}`,
506+
100,
507+
);
508+
list.push({ address: address.plain(), amount: amount });
509+
}
510+
return list;
511+
}
512+
455513
public async generateRandomKey(fieldName: string, message: string, networkType: NetworkType): Promise<string> {
456514
return this.promptText(fieldName, message, Account.generateNewAccount(networkType).privateKey, CommandUtils.isValidPrivateKey);
457515
}

test/commands/init.test.ts

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
import 'mocha';
1818
import { join } from 'path';
1919
import { FileSystemService, LoggerFactory, LogType } from 'symbol-bootstrap';
20+
import { Account, NetworkType } from 'symbol-sdk';
2021
import { InitService } from '../../src';
2122
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
2223
// @ts-ignore
@@ -51,6 +52,8 @@ describe('Init', () => {
5152

5253
it('network2 init', async () => {
5354
// Given this prompts
55+
const distributionAddress1 = Account.createFromPrivateKey(TestUtils.toKey('D1'), NetworkType.MAIN_NET).address.plain();
56+
const distributionAddress2 = Account.createFromPrivateKey(TestUtils.toKey('D2'), NetworkType.MAIN_NET).address.plain();
5457
StdUtils.in([
5558
'\n',
5659
'\n',
@@ -63,19 +66,28 @@ describe('Init', () => {
6366
`${TestUtils.toKey('A')}`,
6467
'\n',
6568
'1626575785\n',
66-
'pirate\n',
69+
'pirate\n', //Mosaic 1
6770
'gold\n',
68-
`${TestUtils.toKey('B')}`,
71+
`${TestUtils.toKey('B')}`, // Nemesis signer.
6972
'\n',
70-
`${TestUtils.toKey('C')}`,
73+
`${TestUtils.toKey('C')}`, // Founder
7174
'\n',
7275
'Y\n',
73-
`${TestUtils.toKey('D')}`,
76+
`${TestUtils.toKey('D')}`, // Faucet
7477
'\n',
7578
'\n',
76-
`${TestUtils.toKey('E')}\n`,
77-
`${TestUtils.toKey('F')}\n`,
78-
`${TestUtils.toKey('AA')}\n`,
79+
'y\n', // Yes, enter distribution addresses
80+
distributionAddress1,
81+
'\n',
82+
`500\n`,
83+
'y\n', // Yes, enter distribution addresses
84+
distributionAddress2,
85+
'\n',
86+
`100\n`,
87+
'n\n', // No more distribution
88+
`${TestUtils.toKey('E')}\n`, //sink
89+
`${TestUtils.toKey('F')}\n`, //sink
90+
`${TestUtils.toKey('AA')}\n`, //sink
7991
//First node
8092
`\n`,
8193
'2',
480 Bytes
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.

test/networkExamples/network2/expected/nemesis-seed/summary.txt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,11 @@
44
Voting Balance: 6000000000000
55
*
66
Generation Hash: D43808D5F3FDA9AC541CCB75F00F7077202787C4DA7867BF06AB37B1D7B4EA0C
7-
Transactions Hash: 4E9FE39B09F12B6241B6DF1EA1D63E58A8709E4520106602463A2467BBCB8410
7+
Transactions Hash: 9AE6469ED739214ECD592712B1C82CA34F801C714E69788E3822319622C753B0
88
Receipts Hash: FDDDDD29B4408DF2044CBA322E35BA989A9F92B81D49E3CC141E46613D226287
9-
State Hash: 6E427011A127AEEE13831EC9A7EF93422C47A087BADBD2C8C9A4975EE13AF234
9+
State Hash: A7F42760454F1576B1F9BCF3F6B75C462ECBBF163379ACB43BED6A6AFEF5F712
1010
--- Components (9) ---
11-
+ 93DFC0E053587BA8D384EC4AEF71F2C14C91C585A720FF32A3E456762D89453E
11+
+ A3A0D88B9276114D3F4A0E8C563124C946BBF3F7165548A7F8D9D57C0B089315
1212
+ AF037B19C5461AF9D214DCF21406555E7CC960E1084A674E6167C31CE5A3F84B
1313
+ DD42D8D1905B40D7CAA4B0BE5E8ABC9292A25A62CBBBD81203D58A58DC387CA7
1414
+ 0000000000000000000000000000000000000000000000000000000000000000

0 commit comments

Comments
 (0)