| 119 | } |
| 120 | |
| 121 | export class LocalDevAccountCreator { |
| 122 | static optionsSchema = z.object({ |
| 123 | // Number of validators, default is 5. |
| 124 | numValidators: z.number().min(1).optional(), |
| 125 | // number of extra prefunded accounts, default is 0. |
| 126 | numExtraAccounts: z.number().min(0).optional(), |
| 127 | // number of extra minters, default is 0. |
| 128 | numExtraMinters: z.number().min(0).optional(), |
| 129 | // override public keys for validators, format: ID:KEY,ID:KEY |
| 130 | overridePublicKeys: z.string().optional(), |
| 131 | // per-validator voting powers; when omitted every validator gets the default (20) |
| 132 | votingPowers: z.array(z.number().min(1)).optional(), |
| 133 | }) |
| 134 | |
| 135 | numValidators: number |
| 136 | numExtraAccounts: number |
| 137 | numExtraMinters: number |
| 138 | overridePublicKeys: Map<number, Hex> |
| 139 | votingPowers?: number[] |
| 140 | mnemonic: string |
| 141 | |
| 142 | constructor(options?: z.infer<typeof LocalDevAccountCreator.optionsSchema>) { |
| 143 | const { |
| 144 | numValidators = 5, |
| 145 | numExtraAccounts = 0, |
| 146 | numExtraMinters = 0, |
| 147 | overridePublicKeys = defaultOverridePublicKeys(), |
| 148 | votingPowers, |
| 149 | } = options ? LocalDevAccountCreator.optionsSchema.parse(options) : {} |
| 150 | this.numValidators = numValidators |
| 151 | this.numExtraAccounts = numExtraAccounts |
| 152 | this.numExtraMinters = numExtraMinters |
| 153 | this.overridePublicKeys = parseOverridePublicKeys(overridePublicKeys) |
| 154 | if (votingPowers && votingPowers.length !== numValidators) { |
| 155 | throw new Error(`votingPowers length (${votingPowers.length}) must match numValidators (${numValidators})`) |
| 156 | } |
| 157 | this.votingPowers = votingPowers |
| 158 | this.mnemonic = 'test test test test test test test test test test test junk' |
| 159 | } |
| 160 | |
| 161 | // Default accounts, BIP44: m/44'/60'/0'/0/{0~9} |
| 162 | defaultAccounts = () => |
| 163 | Array.from({ length: 10 }).map((_, i) => mnemonicToAccount(this.mnemonic, { path: `m/44'/60'/0'/0/${i}` })) |
| 164 | |
| 165 | namedAccounts = <T>(accounts: T[]) => { |
| 166 | const [sender, receiver] = accounts |
| 167 | const [operator, admin, proxyAdmin] = accounts.slice(7, 10) |
| 168 | return { sender, receiver, operator, admin, proxyAdmin } |
| 169 | } |
| 170 | |
| 171 | // Extra prefunded accounts for load testing, BIP44: m/44'/60'/1'/0/{index} |
| 172 | extraPrefundAccounts = () => |
| 173 | Array.from({ length: this.numExtraAccounts }).map((_, i) => |
| 174 | mnemonicToAccount(this.mnemonic, { path: `m/44'/60'/1'/0/${i}` }), |
| 175 | ) |
| 176 | |
| 177 | // Extra minters for load testing, share the same BIP44 path with extraPrefundAccounts. |
| 178 | extraMinters = () => |