@polkadot/util-crypto#randomAsHex TypeScript Examples

The following examples show how to use @polkadot/util-crypto#randomAsHex. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: runner.ts    From polkadot-launch with MIT License 6 votes vote down vote up
async function generateNodeKeys(
	config: ResolvedLaunchConfig
): Promise<string[]> {
	var bootnodes = [];
	for (const node of config.relaychain.nodes) {
		if (!node.nodeKey) {
			node.nodeKey = hexStripPrefix(randomAsHex(32));
		}

		let pair = await libp2pKeys.generateKeyPairFromSeed(
			"Ed25519",
			hexToU8a(hexAddPrefix(node.nodeKey!)),
			1024
		);
		let peerId: PeerId = await PeerId.createFromPrivKey(pair.bytes);
		bootnodes.push(
			`/ip4/127.0.0.1/tcp/${node.port}/p2p/${peerId.toB58String()}`
		);
	}

	return bootnodes;
}
Example #2
Source File: test-crowdloan.ts    From moonbeam with GNU General Public License v3.0 5 votes vote down vote up
describeDevMoonbeam("Crowdloan", (context) => {
  let genesisAccount: KeyringPair, sudoAccount: KeyringPair, toUpdateAccount: KeyringPair;

  before("Setup genesis account and relay accounts", async () => {
    const keyring = new Keyring({ type: "ethereum" });
    genesisAccount = await keyring.addFromUri(GENESIS_ACCOUNT_PRIVATE_KEY, null, "ethereum");
    sudoAccount = await keyring.addFromUri(ALITH_PRIV_KEY, null, "ethereum");
    const seed = randomAsHex(32);
    toUpdateAccount = await keyring.addFromUri(seed, null, "ethereum");
  });

  it("should be able to update reward address", async function () {
    await context.polkadotApi.tx.sudo
      .sudo(
        context.polkadotApi.tx.crowdloanRewards.initializeRewardVec([
          [relayChainAddress, GENESIS_ACCOUNT, 3_000_000n * GLMR],
        ])
      )
      .signAndSend(sudoAccount);
    await context.createBlock();

    let initBlock = (await context.polkadotApi.query.crowdloanRewards.initRelayBlock()) as any;

    // Complete initialization
    await context.polkadotApi.tx.sudo
      .sudo(
        context.polkadotApi.tx.crowdloanRewards.completeInitialization(
          initBlock.toBigInt() + VESTING_PERIOD
        )
      )
      .signAndSend(sudoAccount);
    await context.createBlock();

    let isInitialized = await context.polkadotApi.query.crowdloanRewards.initialized();

    expect(isInitialized.toJSON()).to.be.true;

    // GENESIS_ACCOUNT should be in accounts pauable
    let rewardInfo = await getAccountPayable(context, GENESIS_ACCOUNT);

    expect(rewardInfo.totalReward.toBigInt()).to.equal(3_000_000n * GLMR);

    expect(rewardInfo.claimedReward.toBigInt()).to.equal(900_000n * GLMR);

    // three blocks elapsed
    let claimed = await calculate_vested_amount(
      context,
      rewardInfo.totalReward,
      rewardInfo.claimedReward,
      2
    );

    await context.polkadotApi.tx.crowdloanRewards.claim().signAndSend(genesisAccount);

    await context.createBlock();

    // Claimed amount should match
    const claimedRewards = (await getAccountPayable(context, GENESIS_ACCOUNT)).claimedReward;

    expect(claimedRewards.toBigInt()).to.equal(claimed);

    // Let's update the reward address
    await context.polkadotApi.tx.crowdloanRewards
      .updateRewardAddress(toUpdateAccount.address)
      .signAndSend(genesisAccount);
    await context.createBlock();

    // GENESIS_ACCOUNT should no longer be in accounts payable
    expect(await getAccountPayable(context, GENESIS_ACCOUNT)).to.be.null;

    // toUpdateAccount should be in accounts paYable
    rewardInfo = await getAccountPayable(context, toUpdateAccount.address);

    expect(rewardInfo.totalReward.toBigInt()).to.equal(3_000_000n * GLMR);

    expect(rewardInfo.claimedReward.toBigInt()).to.equal(claimed);
  });
});
Example #3
Source File: test-crowdloan.ts    From moonbeam with GNU General Public License v3.0 5 votes vote down vote up
describeDevMoonbeam("Crowdloan", (context) => {
  let genesisAccount: KeyringPair,
    sudoAccount: KeyringPair,
    toUpdateAccount: KeyringPair,
    proxy: KeyringPair;

  before("Setup genesis account and relay accounts", async () => {
    const keyring = new Keyring({ type: "ethereum" });
    genesisAccount = await keyring.addFromUri(GENESIS_ACCOUNT_PRIVATE_KEY, null, "ethereum");
    sudoAccount = await keyring.addFromUri(ALITH_PRIV_KEY, null, "ethereum");
    proxy = keyring.addFromUri(BALTATHAR_PRIVATE_KEY, null, "ethereum");
    const seed = randomAsHex(32);
    toUpdateAccount = await keyring.addFromUri(seed, null, "ethereum");
  });

  it("should be able to call crowdloan rewards with non-transfer proxy", async function () {
    await context.polkadotApi.tx.sudo
      .sudo(
        context.polkadotApi.tx.crowdloanRewards.initializeRewardVec([
          [relayChainAddress, GENESIS_ACCOUNT, 3_000_000n * GLMR],
        ])
      )
      .signAndSend(sudoAccount);
    await context.createBlock();

    let initBlock = (await context.polkadotApi.query.crowdloanRewards.initRelayBlock()) as any;

    // Complete initialization
    await context.polkadotApi.tx.sudo
      .sudo(
        context.polkadotApi.tx.crowdloanRewards.completeInitialization(
          initBlock.toBigInt() + VESTING_PERIOD
        )
      )
      .signAndSend(sudoAccount);
    await context.createBlock();

    let isInitialized = await context.polkadotApi.query.crowdloanRewards.initialized();

    expect(isInitialized.toJSON()).to.be.true;

    // GENESIS_ACCOUNT should be in accounts pauable
    let rewardInfo = await getAccountPayable(context, GENESIS_ACCOUNT);

    expect(rewardInfo.totalReward.toBigInt()).to.equal(3_000_000n * GLMR);

    expect(rewardInfo.claimedReward.toBigInt()).to.equal(900_000n * GLMR);

    // CreateProxy
    await context.polkadotApi.tx.proxy
      .addProxy(proxy.address, "NonTransfer", 0)
      .signAndSend(genesisAccount);
    await context.createBlock();

    // three blocks elapsed
    let claimed = await calculate_vested_amount(
      context,
      rewardInfo.totalReward,
      rewardInfo.claimedReward,
      3
    );

    // Claim with proxy
    await context.polkadotApi.tx.proxy
      .proxy(genesisAccount.address, null, context.polkadotApi.tx.crowdloanRewards.claim())
      .signAndSend(proxy);

    await context.createBlock();

    // Claimed amount should match
    const claimedRewards = (await getAccountPayable(context, GENESIS_ACCOUNT)).claimedReward;

    expect(claimedRewards.toBigInt()).to.equal(claimed);
  });
});
Example #4
Source File: test-crowdloan.ts    From moonbeam with GNU General Public License v3.0 5 votes vote down vote up
describeDevMoonbeam("Crowdloan", (context) => {
  let genesisAccount: KeyringPair,
    sudoAccount: KeyringPair,
    toUpdateAccount: KeyringPair,
    proxy: KeyringPair;

  before("Setup genesis account and relay accounts", async () => {
    const keyring = new Keyring({ type: "ethereum" });
    genesisAccount = await keyring.addFromUri(GENESIS_ACCOUNT_PRIVATE_KEY, null, "ethereum");
    sudoAccount = await keyring.addFromUri(ALITH_PRIV_KEY, null, "ethereum");
    proxy = keyring.addFromUri(BALTATHAR_PRIVATE_KEY, null, "ethereum");
    const seed = randomAsHex(32);
    toUpdateAccount = await keyring.addFromUri(seed, null, "ethereum");
  });

  it("should NOT be able to call non-claim extrinsic with non-transfer proxy", async function () {
    await context.polkadotApi.tx.sudo
      .sudo(
        context.polkadotApi.tx.crowdloanRewards.initializeRewardVec([
          [relayChainAddress, GENESIS_ACCOUNT, 3_000_000n * GLMR],
        ])
      )
      .signAndSend(sudoAccount);
    await context.createBlock();

    let initBlock = (await context.polkadotApi.query.crowdloanRewards.initRelayBlock()) as any;

    // Complete initialization
    await context.polkadotApi.tx.sudo
      .sudo(
        context.polkadotApi.tx.crowdloanRewards.completeInitialization(
          initBlock.toBigInt() + VESTING_PERIOD
        )
      )
      .signAndSend(sudoAccount);
    await context.createBlock();

    let isInitialized = await context.polkadotApi.query.crowdloanRewards.initialized();

    expect(isInitialized.toJSON()).to.be.true;

    // GENESIS_ACCOUNT should be in accounts pauable
    let rewardInfo = await getAccountPayable(context, GENESIS_ACCOUNT);

    expect(rewardInfo.totalReward.toBigInt()).to.equal(3_000_000n * GLMR);

    expect(rewardInfo.claimedReward.toBigInt()).to.equal(900_000n * GLMR);

    // CreateProxy
    await context.polkadotApi.tx.proxy
      .addProxy(proxy.address, "NonTransfer", 0)
      .signAndSend(genesisAccount);
    await context.createBlock();

    // Should not be ablte to do this
    let { events } = await createBlockWithExtrinsic(
      context,
      proxy,
      context.polkadotApi.tx.proxy.proxy(
        genesisAccount.address,
        null,
        context.polkadotApi.tx.crowdloanRewards.updateRewardAddress(proxy.address)
      )
    );
    expect(events[1].toHuman().method).to.eq("ProxyExecuted");
    expect(events[1].data[0].toString()).to.be.eq(
      `{"err":{"module":{"index":0,"error":"0x05000000"}}}`
    );

    // Genesis account still has the money
    rewardInfo = await getAccountPayable(context, GENESIS_ACCOUNT);

    expect(rewardInfo.totalReward.toBigInt()).to.equal(3_000_000n * GLMR);

    expect(rewardInfo.claimedReward.toBigInt()).to.equal(900_000n * GLMR);
  });
});
Example #5
Source File: test-precompile-author-mapping.ts    From moonbeam with GNU General Public License v3.0 5 votes vote down vote up
describeDevMoonbeamAllEthTxTypes("Precompiles - author mapping", (context) => {
  it("allows to add association", async function () {
    const contractData = await getCompiled("AuthorMapping");
    const iFace = new ethers.utils.Interface(contractData.contract.abi);
    const { contract, rawTx } = await createContract(context, "AuthorMapping");
    const address = contract.options.address;
    await context.createBlock({ transactions: [rawTx] });
    const seed = randomAsHex(32);

    const mappingKeyRing = new Keyring({ type: "sr25519" });
    // add the account
    let mappingAccount = await mappingKeyRing.addFromUri(seed, null, "sr25519");

    const data = iFace.encodeFunctionData(
      // action
      "add_association",
      [mappingAccount.publicKey]
    );

    const base_fee = await context.web3.eth.getGasPrice();

    const tx = await createTransaction(context, {
      from: GENESIS_ACCOUNT,
      privateKey: GENESIS_ACCOUNT_PRIVATE_KEY,
      value: "0x0",
      gas: "0x200000",
      gasPrice: base_fee,
      to: ADDRESS_AUTHOR_MAPPING,
      data,
    });

    const block = await context.createBlock({
      transactions: [tx],
    });

    const receipt = await context.web3.eth.getTransactionReceipt(block.txResults[0].result);
    expect(receipt.status).to.equal(true);

    const registerInfo = await getMappingInfo(context, u8aToHex(mappingAccount.publicKey));
    expect(await registerInfo.account).to.eq(GENESIS_ACCOUNT);
    expect(await registerInfo.deposit).to.eq(DEFAULT_GENESIS_MAPPING);
  });
});
Example #6
Source File: test-precompile-author-mapping.ts    From moonbeam with GNU General Public License v3.0 5 votes vote down vote up
describeDevMoonbeamAllEthTxTypes("Precompiles - author mapping", (context) => {
  let firstMappingAccount, secondMappingAccount;
  before("First add association", async () => {
    // We will work with genesis account
    const keyring = new Keyring({ type: "ethereum" });
    let genesisAccount = await keyring.addFromUri(GENESIS_ACCOUNT_PRIVATE_KEY, null, "ethereum");

    // lets generate 2 seeds for 2 sr25519 addresses
    const seed = randomAsHex(32);
    const seed2 = randomAsHex(32);

    const mappingKeyRing = new Keyring({ type: "sr25519" });
    // accounts
    firstMappingAccount = await mappingKeyRing.addFromUri(seed, null, "sr25519");
    secondMappingAccount = await mappingKeyRing.addFromUri(seed2, null, "sr25519");

    // Add association
    await context.polkadotApi.tx.authorMapping
      .addAssociation(firstMappingAccount.publicKey)
      .signAndSend(genesisAccount);
    await context.createBlock();

    // Verify association was added
    const registerInfo = await getMappingInfo(context, u8aToHex(firstMappingAccount.publicKey));
    expect(await registerInfo.account).to.eq(GENESIS_ACCOUNT);
    expect(await registerInfo.deposit).to.eq(DEFAULT_GENESIS_MAPPING);
  });
  it("allows to update association", async function () {
    const contractData = await getCompiled("AuthorMapping");
    const iFace = new ethers.utils.Interface(contractData.contract.abi);
    const { contract, rawTx } = await createContract(context, "AuthorMapping");
    const address = contract.options.address;
    await context.createBlock({ transactions: [rawTx] });

    const data = iFace.encodeFunctionData(
      // action
      "update_association",
      [firstMappingAccount.publicKey, secondMappingAccount.publicKey]
    );

    const base_fee = await context.web3.eth.getGasPrice();

    const tx = await createTransaction(context, {
      from: GENESIS_ACCOUNT,
      privateKey: GENESIS_ACCOUNT_PRIVATE_KEY,
      value: "0x0",
      gas: "0x200000",
      gasPrice: base_fee,
      to: ADDRESS_AUTHOR_MAPPING,
      data,
    });

    const block = await context.createBlock({
      transactions: [tx],
    });

    const receipt = await context.web3.eth.getTransactionReceipt(block.txResults[0].result);
    expect(receipt.status).to.equal(true);

    // Verify we updated firstMappingAccount for secondMappingAccount
    const secondRegisterInfo = await getMappingInfo(
      context,
      u8aToHex(secondMappingAccount.publicKey)
    );
    expect(await secondRegisterInfo.account).to.eq(GENESIS_ACCOUNT);
    expect(await secondRegisterInfo.deposit).to.eq(DEFAULT_GENESIS_MAPPING);

    const firstRegisterInfo = await getMappingInfo(
      context,
      u8aToHex(firstMappingAccount.publicKey)
    );
    expect(firstRegisterInfo).to.eq(null);
  });
});
Example #7
Source File: test-precompile-author-mapping.ts    From moonbeam with GNU General Public License v3.0 5 votes vote down vote up
describeDevMoonbeamAllEthTxTypes("Precompiles - author mapping", (context) => {
  let mappingAccount;
  before("First add association", async () => {
    // We will work with genesis account
    const keyring = new Keyring({ type: "ethereum" });
    let genesisAccount = await keyring.addFromUri(GENESIS_ACCOUNT_PRIVATE_KEY, null, "ethereum");

    const seed = randomAsHex(32);
    const mappingKeyRing = new Keyring({ type: "sr25519" });
    // account
    mappingAccount = await mappingKeyRing.addFromUri(seed, null, "sr25519");

    // Add association
    await context.polkadotApi.tx.authorMapping
      .addAssociation(mappingAccount.publicKey)
      .signAndSend(genesisAccount);
    await context.createBlock();

    // Verify association was added
    const registerInfo = await getMappingInfo(context, u8aToHex(mappingAccount.publicKey));
    expect(await registerInfo.account).to.eq(GENESIS_ACCOUNT);
    expect(await registerInfo.deposit).to.eq(DEFAULT_GENESIS_MAPPING);
  });
  it("allows to clear association", async function () {
    const contractData = await getCompiled("AuthorMapping");
    const iFace = new ethers.utils.Interface(contractData.contract.abi);
    const { contract, rawTx } = await createContract(context, "AuthorMapping");
    const address = contract.options.address;
    await context.createBlock({ transactions: [rawTx] });

    const data = iFace.encodeFunctionData(
      // action
      "clear_association",
      [mappingAccount.publicKey]
    );

    const base_fee = await context.web3.eth.getGasPrice();

    const tx = await createTransaction(context, {
      from: GENESIS_ACCOUNT,
      privateKey: GENESIS_ACCOUNT_PRIVATE_KEY,
      value: "0x0",
      gas: "0x200000",
      gasPrice: base_fee,
      to: ADDRESS_AUTHOR_MAPPING,
      data,
    });

    const block = await context.createBlock({
      transactions: [tx],
    });

    const receipt = await context.web3.eth.getTransactionReceipt(block.txResults[0].result);
    expect(receipt.status).to.equal(true);

    // Verify we removed the association
    const firstRegisterInfo = await getMappingInfo(context, u8aToHex(mappingAccount.publicKey));
    expect(firstRegisterInfo).to.eq(null);
  });
});
Example #8
Source File: Program.ts    From gear-js with GNU General Public License v3.0 5 votes vote down vote up
/**
   * @param program Upload program data
   * @param meta Metadata
   * @returns ProgramId
   * @example
   * ```javascript
   * const code = fs.readFileSync('path/to/program.opt.wasm');
   * const meta = await getWasmMetadata(fs.readFileSync('path/to/program.meta.wasm'));
   * const api = await GearApi.create();
   * const { programId, salt, submitted } = api.program.submit({
   *   code,
   *   initPayload: {field: 'someValue'},
   *   gasLimit: 20_000_000,
   * }, meta)
   * api.program.signAndSend(account, (events) => {
   *   events.forEach(({event}) => console.log(event.toHuman()))
   * })
   * ```
   */
  submit(
    program: {
      code: Buffer | Uint8Array;
      salt?: `0x${string}`;
      initPayload?: string | any;
      gasLimit: u64 | AnyNumber;
      value?: BalanceOf | AnyNumber;
    },
    meta?: Metadata,
    messageType?: string,
  ): { programId: Hex; salt: Hex; submitted: SubmittableExtrinsic<'promise', ISubmittableResult> } {
    const salt = program.salt || randomAsHex(20);
    const code = this.createType.create('bytes', Array.from(program.code)) as Bytes;
    let payload = createPayload(this.createType, messageType || meta?.init_input, program.initPayload, meta);
    try {
      this.submitted = this.api.tx.gear.submitProgram(code, salt, payload, program.gasLimit, program.value || 0);
      const programId = generateProgramId(code, salt);
      return { programId, salt, submitted: this.submitted };
    } catch (error) {
      throw new SubmitProgramError();
    }
  }
Example #9
Source File: test-assets-sufficients.ts    From moonbeam with GNU General Public License v3.0 4 votes vote down vote up
describeDevMoonbeam(
  "Pallet Assets - Sufficient tests: is_sufficient to true",
  (context) => {
    let sudoAccount, assetId;
    before("Setup contract and mock balance", async () => {
      const keyring = new Keyring({ type: "ethereum" });
      sudoAccount = await keyring.addFromUri(ALITH_PRIV_KEY, null, "ethereum");
      // We need to mint units with sudo.setStorage, as we dont have xcm mocker yet
      // And we need relay tokens for issuing a transaction to be executed in the relay
      const balance = new BN("100000000000000");
      const assetBalance = context.polkadotApi.createType("PalletAssetsAssetAccount", {
        balance: balance,
      });
      assetId = context.polkadotApi.createType(
        "u128",
        new BN("42259045809535163221576417993425387648")
      );

      const assetDetails = context.polkadotApi.createType("PalletAssetsAssetDetails", {
        supply: balance,
        isSufficient: true,
        minBalance: 1,
      });

      await mockAssetBalance(
        context,
        assetBalance,
        assetDetails,
        sudoAccount,
        assetId,
        ALITH,
        true
      );

      await context.createBlock();
      let alithBalance = (await context.polkadotApi.query.assets.account(assetId, ALITH)) as any;
      expect(alithBalance.unwrap()["balance"].eq(new BN(100000000000000))).to.equal(true);
    });

    it("Send MOVR and assets to an account, then drain assets, then MOVR", async function () {
      // We are going to use a fresh account here, since we mocked the asset balance
      const keyring = new Keyring({ type: "ethereum" });
      const alith = await keyring.addFromUri(ALITH_PRIV_KEY, null, "ethereum");
      const seed = randomAsHex(32);
      const transferAmount = new BN("10000000000000");

      let freshAccount = await keyring.addFromUri(seed, null, "ethereum");

      // We transfer Assets to freshAccount, which should increase sufficients
      await context.polkadotApi.tx.assets
        .transfer(assetId, freshAccount.address, transferAmount)
        .signAndSend(alith);

      await context.createBlock();

      let freshAccountBalance = (await context.polkadotApi.query.assets.account(
        assetId,
        freshAccount.address
      )) as any;

      expect(freshAccountBalance.unwrap()["balance"].eq(new BN(10000000000000))).to.equal(true);

      expect(
        (
          (await context.polkadotApi.query.system.account(freshAccount.address)) as any
        ).sufficients.toBigInt()
      ).to.eq(1n);
      // Providers should still be 0
      expect(
        (
          (await context.polkadotApi.query.system.account(freshAccount.address)) as any
        ).providers.toBigInt()
      ).to.eq(0n);

      // We transfer a good amount to be able to pay for fees
      await context.polkadotApi.tx.balances
        .transfer(freshAccount.address, 1n * GLMR)
        .signAndSend(alith);
      await context.createBlock();

      expect(
        (
          (await context.polkadotApi.query.system.account(freshAccount.address)) as any
        ).sufficients.toBigInt()
      ).to.eq(1n);

      // Providers should now be 1
      expect(
        (
          (await context.polkadotApi.query.system.account(freshAccount.address)) as any
        ).providers.toBigInt()
      ).to.eq(1n);

      // Let's drain assets
      await context.polkadotApi.tx.assets
        .transfer(assetId, BALTATHAR, transferAmount)
        .signAndSend(freshAccount);

      await context.createBlock();

      // Lets drain native token
      // First calculate fee
      // Then grab balance of freshAccount
      // Then we just transfer out balance of freshAccount - fee
      const fee = (
        await context.polkadotApi.tx.balances.transfer(ALITH, 1n * GLMR).paymentInfo(freshAccount)
      ).partialFee as any;

      let freshAccountBalanceNativeToken = (
        (await context.polkadotApi.query.system.account(freshAccount.address)) as any
      ).data.free.toBigInt();

      await context.polkadotApi.tx.balances
        .transfer(BALTATHAR, freshAccountBalanceNativeToken - BigInt(fee))
        .signAndSend(freshAccount);

      await context.createBlock();

      freshAccountBalance = (await context.polkadotApi.query.assets.account(
        assetId,
        freshAccount.address
      )) as any;
      expect(freshAccountBalance.isNone).to.equal(true);

      // Sufficients should go to 0
      expect(
        (
          (await context.polkadotApi.query.system.account(freshAccount.address)) as any
        ).sufficients.toBigInt()
      ).to.eq(0n);
      // Providers should be 1
      expect(
        (
          (await context.polkadotApi.query.system.account(freshAccount.address)) as any
        ).providers.toBigInt()
      ).to.eq(1n);

      // Nonce should be 1
      expect(
        (
          (await context.polkadotApi.query.system.account(freshAccount.address)) as any
        ).providers.toBigInt()
      ).to.eq(1n);

      // But balance of MOVR should be 0
      expect(
        (
          (await context.polkadotApi.query.system.account(freshAccount.address)) as any
        ).data.free.toBigInt()
      ).to.eq(0n);
    });
  },
  "Legacy",
  true
);
Example #10
Source File: test-assets-sufficients.ts    From moonbeam with GNU General Public License v3.0 4 votes vote down vote up
describeDevMoonbeam(
  "Pallet Assets - Sufficient tests: is_sufficient to true",
  (context) => {
    let sudoAccount, assetId;
    before("Setup contract and mock balance", async () => {
      const keyring = new Keyring({ type: "ethereum" });
      sudoAccount = await keyring.addFromUri(ALITH_PRIV_KEY, null, "ethereum");
      // We need to mint units with sudo.setStorage, as we dont have xcm mocker yet
      // And we need relay tokens for issuing a transaction to be executed in the relay
      const balance = new BN("100000000000000");
      const assetBalance = context.polkadotApi.createType("PalletAssetsAssetAccount", {
        balance: balance,
      });
      assetId = context.polkadotApi.createType(
        "u128",
        new BN("42259045809535163221576417993425387648")
      );

      const assetDetails = context.polkadotApi.createType("PalletAssetsAssetDetails", {
        supply: balance,
        isSufficient: true,
        minBalance: 1,
      });

      await mockAssetBalance(
        context,
        assetBalance,
        assetDetails,
        sudoAccount,
        assetId,
        ALITH,
        true
      );

      await context.createBlock();
      let alithBalance = (await context.polkadotApi.query.assets.account(assetId, ALITH)) as any;
      expect(alithBalance.unwrap()["balance"].eq(new BN(100000000000000))).to.equal(true);
    });

    it("Send MOVR and assets to an account, then drain assets, dont drain MOVR", async function () {
      // We are going to use a fresh account here, since we mocked the asset balance
      const keyring = new Keyring({ type: "ethereum" });
      const alith = await keyring.addFromUri(ALITH_PRIV_KEY, null, "ethereum");
      const seed = randomAsHex(32);
      const transferAmount = new BN("10000000000000");

      let freshAccount = await keyring.addFromUri(seed, null, "ethereum");

      // We transfer Assets to freshAccount, which should increase sufficients
      await context.polkadotApi.tx.assets
        .transfer(assetId, freshAccount.address, transferAmount)
        .signAndSend(alith);

      await context.createBlock();

      let freshAccountBalance = (await context.polkadotApi.query.assets.account(
        assetId,
        freshAccount.address
      )) as any;
      expect(freshAccountBalance.unwrap()["balance"].eq(new BN(10000000000000))).to.equal(true);

      expect(
        (
          (await context.polkadotApi.query.system.account(freshAccount.address)) as any
        ).sufficients.toBigInt()
      ).to.eq(1n);
      // Providers should still be 0
      expect(
        (
          (await context.polkadotApi.query.system.account(freshAccount.address)) as any
        ).providers.toBigInt()
      ).to.eq(0n);

      // Lets transfer it the native token. We want to transfer enough to cover for a future fee.
      const fee = (
        await context.polkadotApi.tx.assets
          .transfer(assetId, BALTATHAR, transferAmount)
          .paymentInfo(freshAccount)
      ).partialFee as any;

      await context.polkadotApi.tx.balances
        .transfer(freshAccount.address, BigInt(fee))
        .signAndSend(alith);
      await context.createBlock();

      expect(
        (
          (await context.polkadotApi.query.system.account(freshAccount.address)) as any
        ).sufficients.toBigInt()
      ).to.eq(1n);
      // Providers should now be 1
      expect(
        (
          (await context.polkadotApi.query.system.account(freshAccount.address)) as any
        ).providers.toBigInt()
      ).to.eq(1n);

      // What happens now when we execute such transaction? both MOVR and Assets should be drained.
      await context.polkadotApi.tx.assets
        .transfer(assetId, BALTATHAR, transferAmount)
        .signAndSend(freshAccount);

      await context.createBlock();

      freshAccountBalance = (await context.polkadotApi.query.assets.account(
        assetId,
        freshAccount.address
      )) as any;
      expect(freshAccountBalance.isNone).to.equal(true);

      // Sufficients should go to 0
      expect(
        (
          (await context.polkadotApi.query.system.account(freshAccount.address)) as any
        ).sufficients.toBigInt()
      ).to.eq(0n);
      // Providers should be 1
      expect(
        (
          (await context.polkadotApi.query.system.account(freshAccount.address)) as any
        ).providers.toBigInt()
      ).to.eq(1n);

      // Nonce should be 1
      expect(
        (
          (await context.polkadotApi.query.system.account(freshAccount.address)) as any
        ).providers.toBigInt()
      ).to.eq(1n);

      // But balance of MOVR should be 0
      expect(
        (
          (await context.polkadotApi.query.system.account(freshAccount.address)) as any
        ).data.free.toBigInt() > 0n
      ).to.eq(true);
    });
  },
  "Legacy",
  true
);
Example #11
Source File: test-assets-sufficients.ts    From moonbeam with GNU General Public License v3.0 4 votes vote down vote up
describeDevMoonbeam(
  "Pallet Assets - Sufficient tests: is_sufficient to false",
  (context) => {
    let sudoAccount, assetId;
    before("Setup contract and mock balance", async () => {
      const keyring = new Keyring({ type: "ethereum" });
      sudoAccount = await keyring.addFromUri(ALITH_PRIV_KEY, null, "ethereum");
      // We need to mint units with sudo.setStorage, as we dont have xcm mocker yet
      // And we need relay tokens for issuing a transaction to be executed in the relay
      const balance = new BN("100000000000000");
      const assetBalance = context.polkadotApi.createType("PalletAssetsAssetAccount", {
        balance: balance,
      });
      assetId = context.polkadotApi.createType(
        "u128",
        new BN("42259045809535163221576417993425387648")
      );

      const assetDetails = context.polkadotApi.createType("PalletAssetsAssetDetails", {
        supply: balance,
        isSufficient: false,
        minBalance: 1,
      });

      await mockAssetBalance(
        context,
        assetBalance,
        assetDetails,
        sudoAccount,
        assetId,
        ALITH,
        false
      );

      await context.createBlock();
      let alithBalance = (await context.polkadotApi.query.assets.account(assetId, ALITH)) as any;
      expect(alithBalance.unwrap()["balance"].eq(new BN(100000000000000))).to.equal(true);
    });

    it("Send MOVR and assets to an account, then drain assets, dont drain MOVR", async function () {
      // We are going to use a fresh account here, since we mocked the asset balance
      const keyring = new Keyring({ type: "ethereum" });
      const alith = await keyring.addFromUri(ALITH_PRIV_KEY, null, "ethereum");
      const seed = randomAsHex(32);
      const transferAmount = new BN("10000000000000");

      let freshAccount = await keyring.addFromUri(seed, null, "ethereum");

      // We cannot transfer to freshAccount, since sufficient is false
      await context.polkadotApi.tx.assets
        .transfer(assetId, freshAccount.address, transferAmount)
        .signAndSend(alith);

      await context.createBlock();

      let freshAccountBalance = (await context.polkadotApi.query.assets.account(
        assetId,
        freshAccount.address
      )) as any;
      expect(freshAccountBalance.isNone).to.equal(true);

      expect(
        (
          (await context.polkadotApi.query.system.account(freshAccount.address)) as any
        ).sufficients.toBigInt()
      ).to.eq(0n);
      // Providers should still be 0
      expect(
        (
          (await context.polkadotApi.query.system.account(freshAccount.address)) as any
        ).providers.toBigInt()
      ).to.eq(0n);

      // Lets transfer it the native token. We want to transfer enough to cover for a future fee.
      const fee = (
        await context.polkadotApi.tx.assets
          .transfer(assetId, BALTATHAR, transferAmount)
          .paymentInfo(freshAccount)
      ).partialFee as any;

      // We transfer Balances, which should increase provider
      await context.polkadotApi.tx.balances
        .transfer(freshAccount.address, BigInt(fee))
        .signAndSend(alith);
      await context.createBlock();

      expect(
        (
          (await context.polkadotApi.query.system.account(freshAccount.address)) as any
        ).sufficients.toBigInt()
      ).to.eq(0n);
      // Providers should now be 1
      expect(
        (
          (await context.polkadotApi.query.system.account(freshAccount.address)) as any
        ).providers.toBigInt()
      ).to.eq(1n);

      // We now can transfer assets to freshAccount, since it has a provider
      await context.polkadotApi.tx.assets
        .transfer(assetId, freshAccount.address, transferAmount)
        .signAndSend(alith);

      await context.createBlock();

      freshAccountBalance = (await context.polkadotApi.query.assets.account(
        assetId,
        freshAccount.address
      )) as any;
      expect(freshAccountBalance.unwrap()["balance"].eq(transferAmount)).to.equal(true);

      expect(
        (
          (await context.polkadotApi.query.system.account(freshAccount.address)) as any
        ).sufficients.toBigInt()
      ).to.eq(0n);

      expect(
        (
          (await context.polkadotApi.query.system.account(freshAccount.address)) as any
        ).providers.toBigInt()
      ).to.eq(1n);

      expect(
        (
          (await context.polkadotApi.query.system.account(freshAccount.address)) as any
        ).consumers.toBigInt()
      ).to.eq(1n);

      // What happens now when we execute such transaction? both MOVR and Assets should be drained.
      await context.polkadotApi.tx.assets
        .transfer(assetId, BALTATHAR, transferAmount)
        .signAndSend(freshAccount);

      await context.createBlock();

      freshAccountBalance = (await context.polkadotApi.query.assets.account(
        assetId,
        freshAccount.address
      )) as any;
      expect(freshAccountBalance.isNone).to.equal(true);

      // Sufficients should be 0
      expect(
        (
          (await context.polkadotApi.query.system.account(freshAccount.address)) as any
        ).sufficients.toBigInt()
      ).to.eq(0n);

      // Consumers should be 0
      expect(
        (
          (await context.polkadotApi.query.system.account(freshAccount.address)) as any
        ).consumers.toBigInt()
      ).to.eq(0n);

      // Providers should be 1
      expect(
        (
          (await context.polkadotApi.query.system.account(freshAccount.address)) as any
        ).providers.toBigInt()
      ).to.eq(1n);

      // Nonce should be 1
      expect(
        (
          (await context.polkadotApi.query.system.account(freshAccount.address)) as any
        ).providers.toBigInt()
      ).to.eq(1n);

      // But balance of MOVR should be 0
      expect(
        (
          (await context.polkadotApi.query.system.account(freshAccount.address)) as any
        ).data.free.toBigInt() > 0n
      ).to.eq(true);
    });
  },
  "Legacy",
  true
);
Example #12
Source File: test-crowdloan.ts    From moonbeam with GNU General Public License v3.0 4 votes vote down vote up
describeDevMoonbeam("Crowdloan", (context) => {
  let genesisAccount: KeyringPair,
    sudoAccount: KeyringPair,
    relayAccount: KeyringPair,
    toAssociateAccount: KeyringPair;

  before("Setup genesis account and relay accounts", async () => {
    const keyring = new Keyring({ type: "ethereum" });
    const relayKeyRing = new Keyring({ type: "ed25519" });
    genesisAccount = await keyring.addFromUri(GENESIS_ACCOUNT_PRIVATE_KEY, null, "ethereum");
    sudoAccount = await keyring.addFromUri(ALITH_PRIV_KEY, null, "ethereum");
    const seed = randomAsHex(32);
    // add the account, override to ed25519
    relayAccount = await relayKeyRing.addFromUri(seed, null, "ed25519");
    toAssociateAccount = await keyring.addFromUri(seed, null, "ethereum");
  });

  it("should be able to associate identity", async function () {
    await context.polkadotApi.tx.sudo
      .sudo(
        context.polkadotApi.tx.crowdloanRewards.initializeRewardVec([
          [relayChainAddress, GENESIS_ACCOUNT, 1_500_000n * GLMR],
          [relayAccount.addressRaw, null, 1_500_000n * GLMR],
        ])
      )
      .signAndSend(sudoAccount);
    await context.createBlock();

    let initBlock = (await context.polkadotApi.query.crowdloanRewards.initRelayBlock()) as any;

    // Complete initialization
    await context.polkadotApi.tx.sudo
      .sudo(
        context.polkadotApi.tx.crowdloanRewards.completeInitialization(
          initBlock.toBigInt() + VESTING_PERIOD
        )
      )
      .signAndSend(sudoAccount);
    await context.createBlock();

    let isInitialized = await context.polkadotApi.query.crowdloanRewards.initialized();

    expect(isInitialized.toJSON()).to.be.true;

    // relayAccount should be in the unassociated contributions
    expect(
      (
        (await context.polkadotApi.query.crowdloanRewards.unassociatedContributions(
          relayAccount.addressRaw
        )) as any
      )
        .unwrap()
        .totalReward.toBigInt()
    ).to.equal(1_500_000n * GLMR);

    // toAssociateAccount should not be in accounts payable
    expect(await getAccountPayable(context, toAssociateAccount.address)).to.be.null;

    let message = new Uint8Array([
      ...stringToU8a("<Bytes>"),
      ...stringToU8a("moonbase-"),
      ...toAssociateAccount.addressRaw,
      ...stringToU8a("</Bytes>"),
    ]);
    // Construct the signature
    let signature = {};
    signature["Ed25519"] = relayAccount.sign(message);

    // Associate the identity
    await context.polkadotApi.tx.crowdloanRewards
      .associateNativeIdentity(toAssociateAccount.address, relayAccount.addressRaw, signature)
      .signAndSend(genesisAccount);
    await context.createBlock();

    // relayAccount should no longer be in the unassociated contributions
    expect(
      (
        await context.polkadotApi.query.crowdloanRewards.unassociatedContributions(
          relayAccount.addressRaw
        )
      ).toJSON()
    ).to.be.null;

    // toAssociateAccount should now be in accounts payable
    let rewardInfo = await getAccountPayable(context, toAssociateAccount.address);

    expect(rewardInfo.totalReward.toBigInt()).to.equal(1_500_000n * GLMR);
    expect(rewardInfo.claimedReward.toBigInt()).to.equal(450_000n * GLMR);

    // three blocks elapsed
    let claimed = await calculate_vested_amount(
      context,
      rewardInfo.totalReward,
      rewardInfo.claimedReward,
      3
    );

    await context.polkadotApi.tx.crowdloanRewards.claim().signAndSend(toAssociateAccount);

    await context.createBlock();

    // Claimed amount should match
    expect(
      (await getAccountPayable(context, toAssociateAccount.address)).claimedReward.toBigInt()
    ).to.equal(claimed);
  });
});
Example #13
Source File: test-crowdloan.ts    From moonbeam with GNU General Public License v3.0 4 votes vote down vote up
describeDevMoonbeam("Crowdloan", (context) => {
  let genesisAccount: KeyringPair,
    sudoAccount: KeyringPair,
    relayAccount: KeyringPair,
    relayAccount2: KeyringPair,
    firstAccount: KeyringPair,
    toAssociateAccount: KeyringPair;

  before("Setup genesis account and relay accounts", async () => {
    const keyring = new Keyring({ type: "ethereum" });
    const relayKeyRing = new Keyring({ type: "ed25519" });
    genesisAccount = await keyring.addFromUri(GENESIS_ACCOUNT_PRIVATE_KEY, null, "ethereum");
    sudoAccount = await keyring.addFromUri(ALITH_PRIV_KEY, null, "ethereum");
    const seed = randomAsHex(32);
    // add the account, override to ed25519
    relayAccount = await relayKeyRing.addFromUri(seed, null, "ed25519");
    const seed2 = randomAsHex(32);

    relayAccount2 = await relayKeyRing.addFromUri(seed2, null, "ed25519");

    firstAccount = await keyring.addFromUri(seed, null, "ethereum");

    toAssociateAccount = await keyring.addFromUri(seed2, null, "ethereum");
  });

  it("should be able to change reward address with relay keys", async function () {
    await context.polkadotApi.tx.sudo
      .sudo(
        context.polkadotApi.tx.crowdloanRewards.initializeRewardVec([
          [relayAccount.addressRaw, firstAccount.address, 1_500_000n * GLMR],
          [relayAccount2.addressRaw, firstAccount.address, 1_500_000n * GLMR],
        ])
      )
      .signAndSend(sudoAccount);
    await context.createBlock();

    let initBlock = (await context.polkadotApi.query.crowdloanRewards.initRelayBlock()) as any;

    // Complete initialization
    await context.polkadotApi.tx.sudo
      .sudo(
        context.polkadotApi.tx.crowdloanRewards.completeInitialization(
          initBlock.toBigInt() + VESTING_PERIOD
        )
      )
      .signAndSend(sudoAccount);
    await context.createBlock();

    let isInitialized = await context.polkadotApi.query.crowdloanRewards.initialized();

    expect(isInitialized.toJSON()).to.be.true;

    // toAssociateAccount should not be in accounts payable
    expect(await getAccountPayable(context, toAssociateAccount.address)).to.be.null;

    let message = new Uint8Array([
      ...stringToU8a("<Bytes>"),
      ...stringToU8a("moonbase-"),
      ...toAssociateAccount.addressRaw,
      ...firstAccount.addressRaw,
      ...stringToU8a("</Bytes>"),
    ]);

    // Construct the signatures
    let signature1 = {};
    signature1["Ed25519"] = relayAccount.sign(message);
    let signature2 = {};
    signature2["Ed25519"] = relayAccount2.sign(message);

    let proofs = [
      [relayAccount.addressRaw, signature1],
      [relayAccount2.addressRaw, signature2],
    ];
    // Associate the identity
    await context.polkadotApi.tx.crowdloanRewards
      .changeAssociationWithRelayKeys(toAssociateAccount.address, firstAccount.address, proofs)
      .signAndSend(genesisAccount);
    await context.createBlock();

    // toAssociateAccount should now be in accounts payable
    let rewardInfo = await getAccountPayable(context, toAssociateAccount.address);

    expect(rewardInfo.totalReward.toBigInt()).to.equal(3_000_000n * GLMR);
  });
});
Example #14
Source File: Deploy.tsx    From crust-apps with Apache License 2.0 4 votes vote down vote up
function Deploy ({ codeHash, constructorIndex = 0, onClose, setConstructorIndex }: Props): React.ReactElement<Props> {
  const { t } = useTranslation();
  const { api } = useApi();
  const weight = useWeight();
  const [initTx, setInitTx] = useState<SubmittableExtrinsic<'promise'> | null>(null);
  const [params, setParams] = useState<any[]>([]);
  const [accountId, isAccountIdValid, setAccountId] = useFormField<string | null>(null);
  const [endowment, isEndowmentValid, setEndowment] = useNonZeroBn(ENDOWMENT);
  const [salt, setSalt] = useState(() => randomAsHex());
  const [withSalt, setWithSalt] = useState(false);

  useEffect((): void => {
    setParams([]);
  }, [constructorIndex]);

  const code = useMemo(
    () => store.getCode(codeHash),
    [codeHash]
  );

  const [name, isNameValid, setName] = useNonEmptyString(code && code.json.name);
  const { contractAbi, errorText, isAbiError, isAbiSupplied, isAbiValid, onChangeAbi, onRemoveAbi } = useAbi([code && code.json.abi, code && code.contractAbi], codeHash, true);

  const blueprint = useMemo(
    () => isAbiValid && codeHash && contractAbi
      ? new BlueprintPromise(api, contractAbi, codeHash)
      : null,
    [api, codeHash, contractAbi, isAbiValid]
  );

  const constructOptions = useMemo(
    () => contractAbi
      ? contractAbi.constructors.map((message, index) => ({
        info: message.identifier,
        key: `${index}`,
        text: (
          <MessageSignature
            asConstructor
            message={message}
          />
        ),
        value: index
      }))
      : [],
    [contractAbi]
  );

  useEffect((): void => {
    endowment && setInitTx((): SubmittableExtrinsic<'promise'> | null => {
      if (blueprint) {
        try {
          return blueprint.createContract(constructorIndex, { gasLimit: weight.weight, salt: withSalt ? salt : null, value: endowment }, ...params);
        } catch (error) {
          return null;
        }
      }

      return null;
    });
  }, [blueprint, constructorIndex, endowment, params, salt, weight, withSalt]);

  const _onSuccess = useCallback(
    (result: BlueprintSubmittableResult): void => {
      if (result.contract) {
        keyring.saveContract(result.contract.address.toString(), {
          contract: {
            abi: JSON.stringify(result.contract.abi.json),
            genesisHash: api.genesisHash.toHex()
          },
          name,
          tags: []
        });

        onClose && onClose();
      }
    },
    [api, name, onClose]
  );

  const isSaltValid = !withSalt || (salt && (!salt.startsWith('0x') || isHex(salt)));
  const isValid = isNameValid && isEndowmentValid && weight.isValid && isAccountIdValid && isSaltValid;

  return (
    <Modal header={t('Deploy a contract')}>
      <Modal.Content>
        <InputAddress
          help={t('Specify the user account to use for this deployment. Any fees will be deducted from this account.')}
          isInput={false}
          label={t('deployment account')}
          labelExtra={
            <Available
              label={t<string>('transferrable')}
              params={accountId}
            />
          }
          onChange={setAccountId}
          type='account'
          value={accountId}
        />
        <InputName
          isContract
          isError={!isNameValid}
          onChange={setName}
          value={name || ''}
        />
        {!isAbiSupplied && (
          <ABI
            contractAbi={contractAbi}
            errorText={errorText}
            isError={isAbiError}
            isSupplied={isAbiSupplied}
            isValid={isAbiValid}
            onChange={onChangeAbi}
            onRemove={onRemoveAbi}
          />
        )}
        {contractAbi && (
          <>
            <Dropdown
              help={t<string>('The deployment constructor information for this contract, as provided by the ABI.')}
              isDisabled={contractAbi.constructors.length <= 1}
              label={t('deployment constructor')}
              onChange={setConstructorIndex}
              options={constructOptions}
              value={constructorIndex}
            />
            <Params
              onChange={setParams}
              params={contractAbi.constructors[constructorIndex].args}
              registry={contractAbi.registry}
            />
          </>
        )}
        <InputBalance
          help={t<string>('The allotted endowment for this contract, i.e. the amount transferred to the contract upon instantiation.')}
          isError={!isEndowmentValid}
          label={t<string>('endowment')}
          onChange={setEndowment}
          value={endowment}
        />
        <Input
          help={t<string>('A hex or string value that acts as a salt for this deployment.')}
          isDisabled={!withSalt}
          label={t<string>('unique deployment salt')}
          onChange={setSalt}
          placeholder={t<string>('0x prefixed hex, e.g. 0x1234 or ascii data')}
          value={withSalt ? salt : t<string>('<none>')}
        >
          <Toggle
            isOverlay
            label={t<string>('use deployment salt')}
            onChange={setWithSalt}
            value={withSalt}
          />
        </Input>
        <InputMegaGas
          help={t<string>('The maximum amount of gas that can be used by this deployment, if the code requires more, the deployment will fail.')}
          weight={weight}
        />
      </Modal.Content>
      <Modal.Actions onCancel={onClose}>
        <TxButton
          accountId={accountId}
          extrinsic={initTx}
          icon='upload'
          isDisabled={!isValid || !initTx}
          label={t('Deploy')}
          onClick={onClose}
          onSuccess={_onSuccess}
          withSpinner
        />
      </Modal.Actions>
    </Modal>
  );
}
Example #15
Source File: Step2.tsx    From contracts-ui with GNU General Public License v3.0 4 votes vote down vote up
export function Step2() {
  const {
    data: { accountId, metadata },
    dryRunResult,
    stepBackward,
    currentStep,
    onFinalize,
    onFormChange,
  } = useInstantiate();

  const { value, onChange: onChangeValue, ...valueValidation } = useBalance(10000);
  const dbValue = useDebounce(value);

  const [estimatedWeight, setEstimatedWeight] = useState<OrFalsy<BN>>(null);
  const weight = useWeight(estimatedWeight);
  const dbWeight = useDebounce(weight.weight);

  const storageDepositLimit = useStorageDepositLimit(accountId);
  const dbStorageDepositLimit = useDebounce(storageDepositLimit.value);

  const salt = useFormField<string>(randomAsHex(), value => {
    if (!!value && isHex(value) && value.length === 66) {
      return { isValid: true };
    }

    return { isValid: false, isError: true, message: 'Invalid hex string' };
  });
  const dbSalt = useDebounce(salt.value);

  const [constructorIndex, setConstructorIndex] = useState<number>(0);
  const [deployConstructor, setDeployConstructor] = useState<AbiMessage>();

  const [argValues, setArgValues] = useArgValues(deployConstructor?.args || null);
  const dbArgValues = useDebounce(argValues);

  useEffect(() => {
    setConstructorIndex(0);
    metadata && setDeployConstructor(metadata.constructors[0]);
  }, [metadata, setConstructorIndex]);

  const [isUsingSalt, toggleIsUsingSalt] = useToggle(true);
  const [isUsingStorageDepositLimit, toggleIsUsingStorageDepositLimit] = useToggle();

  const onSubmit = () => {
    onFinalize &&
      onFinalize({
        constructorIndex,
        salt: isUsingSalt ? salt.value : undefined,
        value,
        argValues,
        storageDepositLimit: isUsingStorageDepositLimit ? storageDepositLimit.value : undefined,
        weight: weight.isActive ? weight.weight : estimatedWeight || weight.defaultWeight,
      });
  };

  useEffect((): void => {
    if (
      dryRunResult?.result.isOk &&
      dryRunResult.gasRequired &&
      !estimatedWeight?.eq(dryRunResult.gasRequired)
    ) {
      setEstimatedWeight(dryRunResult.gasRequired);
    }
  }, [
    dryRunResult?.result.isOk,
    dryRunResult?.result.isErr,
    dryRunResult?.gasRequired,
    estimatedWeight,
  ]);

  useEffect((): void => {
    onFormChange &&
      onFormChange({
        constructorIndex,
        salt: isUsingSalt ? dbSalt : null,
        value: dbValue && deployConstructor?.isPayable ? dbValue : null,
        argValues: dbArgValues,
        storageDepositLimit: isUsingStorageDepositLimit ? dbStorageDepositLimit : null,
        weight: weight.isActive ? dbWeight : weight.defaultWeight,
      });
  }, [
    onFormChange,
    constructorIndex,
    deployConstructor,
    dbSalt,
    dbValue,
    dbArgValues,
    dbStorageDepositLimit,
    dbWeight,
    isUsingSalt,
    isUsingStorageDepositLimit,
    weight.defaultWeight,
    weight.isActive,
  ]);

  useEffect(
    (): void => {
      if (!metadata) {
        setEstimatedWeight(null);
        weight.setIsActive(false);
      }
    },
    // eslint-disable-next-line
    [metadata]
  );

  if (currentStep !== 2) return null;

  return metadata ? (
    <>
      <Form>
        <FormField
          help="The constructor to use for this contract deployment."
          id="constructor"
          label="Deployment Constructor"
        >
          <Dropdown
            id="constructor"
            options={createConstructorOptions(metadata.constructors)}
            className="mb-4"
            value={constructorIndex}
            onChange={v => {
              if (isNumber(v)) {
                setConstructorIndex(v);
                setDeployConstructor(metadata.constructors[v]);
              }
            }}
          >
            No constructors found
          </Dropdown>
          {deployConstructor && argValues && (
            <ArgumentForm
              key={`args-${deployConstructor.method}`}
              args={deployConstructor.args}
              registry={metadata.registry}
              setArgValues={setArgValues}
              argValues={argValues}
              className="argument-form"
            />
          )}
        </FormField>
        {deployConstructor?.isPayable && (
          <FormField
            help="The balance to transfer from the `origin` to the newly created contract."
            id="value"
            label="Value"
            {...valueValidation}
          >
            <InputBalance id="value" value={value} onChange={onChangeValue} />
          </FormField>
        )}
        <FormField
          help="A hex or string value that acts as a salt for this deployment."
          id="salt"
          label="Deployment Salt"
          {...getValidation(salt)}
        >
          <InputSalt isActive={isUsingSalt} toggleIsActive={toggleIsUsingSalt} {...salt} />
        </FormField>
        <FormField
          help="The maximum amount of gas (in millions of units) to use for this instantiation. If the transaction requires more, it will fail."
          id="maxGas"
          label="Max Gas Allowed"
          isError={!weight.isValid}
          message={!weight.isValid ? 'Invalid gas limit' : null}
        >
          <InputGas isCall withEstimate {...weight} />
        </FormField>
        <FormField
          help="The maximum balance allowed to be deducted for the new contract's storage deposit."
          id="storageDepositLimit"
          label="Storage Deposit Limit"
          isError={!storageDepositLimit.isValid}
          message={
            !storageDepositLimit.isValid
              ? storageDepositLimit.message || 'Invalid storage deposit limit'
              : null
          }
        >
          <InputStorageDepositLimit
            isActive={isUsingStorageDepositLimit}
            toggleIsActive={toggleIsUsingStorageDepositLimit}
            {...storageDepositLimit}
          />
        </FormField>
      </Form>
      <Buttons>
        <Button
          isDisabled={
            (deployConstructor?.isPayable && !valueValidation.isValid) ||
            (isUsingSalt && !salt.isValid) ||
            !weight.isValid ||
            !storageDepositLimit.isValid ||
            !deployConstructor?.method ||
            !argValues ||
            (dryRunResult && dryRunResult.result.isErr)
          }
          onClick={onSubmit}
          variant="primary"
          data-cy="next-btn"
        >
          Next
        </Button>

        <Button onClick={stepBackward} variant="default">
          Go Back
        </Button>
      </Buttons>
    </>
  ) : null;
}