@polkadot/util#hexToU8a TypeScript Examples

The following examples show how to use @polkadot/util#hexToU8a. 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: util.spec.ts    From crust-apps with Apache License 2.0 7 votes vote down vote up
describe('util', (): void => {
  it('converts a publicKey to address via publicToAddr', (): void => {
    expect(
      publicToAddr(
        hexToU8a(
          '0x836b35a026743e823a90a0ee3b91bf615c6a757e2b60b9e1dc1826fd0dd16106f7bc1e8179f665015f43c6c81f39062fc2086ed849625c06e04697698b21855e'
        )
      )
    ).toEqual('0x0BED7ABd61247635c1973eB38474A2516eD1D884');
  });

  it('converts to valid signature via recoverFromJSON', (): void => {
    expect(
      JSON.stringify(recoverFromJSON('{"address":"0x002309df96687e44280bb72c3818358faeeb699c","msg":"Pay KSMs to the Kusama account:88dc3417d5058ec4b4503e0c12ea1a0a89be200fe98922423d4334014fa6b0ee","sig":"0x55bd020bdbbdc02de34e915effc9b18a99002f4c29f64e22e8dcbb69e722ea6c28e1bb53b9484063fbbfd205e49dcc1f620929f520c9c4c3695150f05a28f52a01","version":"2"}'))
    ).toEqual('{"error":null,"ethereumAddress":"0x002309df96687e44280bb72c3818358faeeb699c","signature":"0x55bd020bdbbdc02de34e915effc9b18a99002f4c29f64e22e8dcbb69e722ea6c28e1bb53b9484063fbbfd205e49dcc1f620929f520c9c4c3695150f05a28f52a01"}');
  });
});
Example #2
Source File: utils.ts    From gear-js with GNU General Public License v3.0 7 votes vote down vote up
export function getTypesFromTypeDef(
  types: Uint8Array | Hex,
  registry?: Registry,
): { typesFromTypeDef: any; namespaces: Map<string, string> } {
  if (!registry) {
    registry = new TypeRegistry();
  }
  const typesFromTypeDef = {};
  const namespaces = new Map<string, string>();
  const portableReg = new PortableRegistry(registry, isHex(types) ? hexToU8a(types) : types, true);
  portableReg.types.forEach(({ id, type: { path } }) => {
    const typeDef = portableReg.getTypeDef(id);
    if (path.length === 0 || (!typeDef.lookupName && !typeDef.lookupNameRoot)) {
      return;
    }
    const name = portableReg.getName(id);
    let camelCasedNamespace = toCamelCase(path.slice(0, path.length - 1));
    if (camelCasedNamespace === name) {
      camelCasedNamespace = path.length > 2 ? toCamelCase(path.slice(0, path.length - 2)) : undefined;
    }
    namespaces.set(name.replace(camelCasedNamespace, ''), name);
    typesFromTypeDef[typeDef.lookupName || typeDef.lookupNameRoot] = typeDef.type.toString();
  });
  return { typesFromTypeDef, namespaces };
}
Example #3
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 #4
Source File: InputFile.tsx    From crust-apps with Apache License 2.0 6 votes vote down vote up
function convertResult (result: ArrayBuffer): Uint8Array {
  const data = new Uint8Array(result);

  // this converts the input (if detected as hex), via the hex conversion route
  if (data[0] === BYTE_STR_0 && data[1] === BYTE_STR_X) {
    let hex = u8aToString(data);

    while (hex[hex.length - 1] === STR_NL) {
      hex = hex.substr(0, hex.length - 1);
    }

    if (isHex(hex)) {
      return hexToU8a(hex);
    }
  }

  return data;
}
Example #5
Source File: CreateType.ts    From gear-js with GNU General Public License v3.0 6 votes vote down vote up
/**
 * @deprecated use `decodeHexTypes`
 */
export function parseHexTypes(hexTypes: string) {
  let { typesFromTypeDef, namespaces } = getTypesFromTypeDef(hexToU8a(hexTypes));
  const result = {};
  namespaces.forEach((value, key) => {
    const replaced = replaceNamespaces(typesFromTypeDef[value], namespaces);
    result[key] = isJSON(replaced) ? JSON.parse(replaced) : replaced;
  });
  return result;
}
Example #6
Source File: SingleAccountSigner.ts    From interbtc-api with Apache License 2.0 6 votes vote down vote up
public async signRaw ({ address, data }: SignerPayloadRaw): Promise<SignerResult> {
      if (address !== this.#keyringPair.address) {
          throw new Error("does not have the keyringPair");
      }

      return new Promise((resolve): void => {
          setTimeout((): void => {
              const signature = u8aToHex(this.#keyringPair.sign(hexToU8a(data)));

              resolve({
                  id: ++id,
                  signature
              });
          }, this.#signDelay);
      });
  }
Example #7
Source File: is-valid-polkadot-address.ts    From interbtc-ui with Apache License 2.0 6 votes vote down vote up
isValidPolkadotAddress = (address: string): boolean => {
  try {
    encodeAddress(isHex(address) ? hexToU8a(address) : decodeAddress(address));

    return true;
  } catch {
    return false;
  }
}
Example #8
Source File: InputFile.tsx    From contracts-ui with GNU General Public License v3.0 6 votes vote down vote up
function convertResult(result: ArrayBuffer): Uint8Array {
  const data = new Uint8Array(result);

  // this converts the input (if detected as hex), via the hex conversion route
  if (data[0] === BYTE_STR_0 && data[1] === BYTE_STR_X) {
    let hex = u8aToString(data);

    while (hex[hex.length - 1] === STR_NL) {
      hex = hex.substr(0, hex.length - 1);
    }

    if (isHex(hex)) {
      return hexToU8a(hex);
    }
  }

  return data;
}
Example #9
Source File: sign.ts    From metamask-snap-polkadot with Apache License 2.0 6 votes vote down vote up
export async function signPayloadRaw(
  wallet: Wallet, api: ApiPromise, payload: SignerPayloadRaw
): Promise<{ signature: string }|void> {
  // ask for confirmation
  const confirmation = await showConfirmationDialog(
    wallet,
    `Do you want to sign following message: \n "${payload.data}" \n with account ${payload.address}`
  );
  // return seed if user confirmed action
  if (confirmation) {
    const keyPair = await getKeyPair(wallet);
    const signedBytes = keyPair.sign(hexToU8a(payload.data));
    return {
      signature: u8aToHex(signedBytes)
    };
  }
}
Example #10
Source File: account.ts    From sdk with Apache License 2.0 6 votes vote down vote up
/**
 * Get svg icons of pubKeys.
 */
async function genPubKeyIcons(pubKeys: string[]) {
  const icons = await genIcons(pubKeys.map((key) => keyring.encodeAddress(hexToU8a(key), 2)));
  return icons.map((i, index) => {
    i[0] = pubKeys[index];
    return i;
  });
}
Example #11
Source File: InputFile.tsx    From subscan-multisig-react with Apache License 2.0 6 votes vote down vote up
function convertResult(result: ArrayBuffer): Uint8Array {
  const data = new Uint8Array(result);

  // this converts the input (if detected as hex), via the hex conversion route
  if (data[0] === BYTE_STR_0 && data[1] === BYTE_STR_X) {
    let hex = u8aToString(data);

    while (hex[hex.length - 1] === STR_NL) {
      hex = hex.substr(0, hex.length - 1);
    }

    if (isHex(hex)) {
      return hexToU8a(hex);
    }
  }

  return data;
}
Example #12
Source File: address.ts    From bodhi.js with Apache License 2.0 6 votes vote down vote up
computeDefaultSubstrateAddress = (evmAddress: string): string => {
  if (!isEvmAddress(evmAddress)) {
    return logger.throwArgumentError('invalid evm address', 'address', evmAddress);
  }

  const address = encodeAddress(u8aFixLength(u8aConcat('evm:', hexToU8a(evmAddress)), 256, true));

  return address.toString();
}
Example #13
Source File: account.test.ts    From metamask-snap-polkadot with Apache License 2.0 6 votes vote down vote up
describe('Test account function: getKeyPair', function() {

  const walletStub = new WalletMock();

  afterEach(function() {
    walletStub.reset();
  });

  it('should return keypair', async function() {
    walletStub.getPluginState.returns({polkadot: {configuration: westendConfiguration}});
    walletStub.getAppKey.returns(testAppKey);
    walletStub.updatePluginState.returnsArg(0);
    const result = await getKeyPair(walletStub);
    expect(walletStub.getAppKey).to.have.been.calledOnce;
    expect(result.address).to.be.eq(testAddress);
    expect(result.publicKey).to.be.deep.eq(hexToU8a(testPublicKey));
  });
});
Example #14
Source File: test-precompile-local-assets-erc20.ts    From moonbeam with GNU General Public License v3.0 5 votes vote down vote up
describeDevMoonbeamAllEthTxTypes(
  "Precompiles - Assets-ERC20 Wasm",
  (context) => {
    let sudoAccount, baltatharAccount, assetId, iFace, assetAddress;
    before("Setup contract and mock balance", async () => {
      const keyring = new Keyring({ type: "ethereum" });
      sudoAccount = await keyring.addFromUri(ALITH_PRIV_KEY, null, "ethereum");
      baltatharAccount = await keyring.addFromUri(BALTATHAR_PRIV_KEY, null, "ethereum");

      // registerAsset
      const { events: eventsRegister } = await createBlockWithExtrinsic(
        context,
        sudoAccount,
        context.polkadotApi.tx.sudo.sudo(
          context.polkadotApi.tx.assetManager.registerLocalAsset(
            baltatharAccount.address,
            baltatharAccount.address,
            true,
            new BN(1)
          )
        )
      );

      // Look for assetId in events
      eventsRegister.forEach((e) => {
        if (e.section.toString() === "assetManager") {
          assetId = e.data[0].toHex();
        }
      });
      assetId = assetId.replace(/,/g, "");

      assetAddress = u8aToHex(new Uint8Array([...hexToU8a("0xFFFFFFFE"), ...hexToU8a(assetId)]));

      const contractData = await getCompiled("LocalAssetExtendedErc20Instance");
      iFace = new ethers.utils.Interface(contractData.contract.abi);
      const { contract, rawTx } = await createContract(context, "LocalAssetExtendedErc20Instance");
      const address = contract.options.address;
      await context.createBlock({ transactions: [rawTx] });
    });
    it("allows to set metadata", async function () {
      let data = iFace.encodeFunctionData(
        // action
        "set_metadata",
        ["Local", "LOC", 12]
      );

      const tx = await createTransaction(context, {
        from: BALTATHAR,
        privateKey: BALTATHAR_PRIV_KEY,
        value: "0x0",
        gas: "0x200000",
        gasPrice: GAS_PRICE,
        to: assetAddress,
        data: 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 metadata = (await context.polkadotApi.query.localAssets.metadata(assetId)) as any;

      expect(u8aToString(metadata.name)).to.eq("Local");
      expect(u8aToString(metadata.symbol)).to.eq("LOC");
      expect(metadata.decimals.toString()).to.eq("12");
    });
  },
  true
);
Example #15
Source File: Provider.ts    From evm-provider.js with Apache License 2.0 5 votes vote down vote up
async _toAddress(addressOrName: string | Promise<string>): Promise<string> {
    const resolved = await addressOrName;
    const address = encodeAddress(
      u8aFixLength(u8aConcat('evm:', hexToU8a(resolved)), 256, true)
    );
    return address.toString();
  }
Example #16
Source File: QrSigner.ts    From sdk with Apache License 2.0 5 votes vote down vote up
export function makeTx(api: ApiPromise, txInfo: any, paramList: any[], ss58: number) {
  return new Promise((resolve) => {
    const signer = txInfo.proxy ? encodeAddress(hexToU8a(txInfo.proxy.pubKey), ss58) : txInfo.sender.address;
    api.derive.tx
      .signingInfo(signer)
      .then(async ({ header, mortalLength, nonce }) => {
        let tx: SubmittableExtrinsic<"promise">;
        // wrap tx with council.propose for treasury propose
        if (txInfo.txName == "treasury.approveProposal") {
          tx = await gov.makeTreasuryProposalSubmission(api, paramList[0], false);
        } else if (txInfo.txName == "treasury.rejectProposal") {
          tx = await gov.makeTreasuryProposalSubmission(api, paramList[0], true);
        } else {
          tx = api.tx[txInfo.module][txInfo.call](...paramList);
        }
        // wrap tx with recovery.asRecovered for proxy tx
        if (txInfo.proxy) {
          tx = api.tx.recovery.asRecovered(txInfo.sender.address, tx);
        }
        const signerPayload = api.registry.createType("SignerPayload", {
          address: signer,
          blockHash: header.hash,
          blockNumber: header ? header.number : 0,
          era: api.registry.createType("ExtrinsicEra", {
            current: header.number,
            period: mortalLength,
          }),
          genesisHash: api.genesisHash,
          method: tx.method,
          nonce,
          signedExtensions: ["CheckNonce"],
          tip: txInfo.tip,
          runtimeVersion: {
            specVersion: api.runtimeVersion.specVersion,
            transactionVersion: api.runtimeVersion.transactionVersion,
          },
          version: api.extrinsicVersion,
        });
        const payload = signerPayload.toPayload();

        // limit size of the transaction
        const qrIsHashed = payload.method.length > 5000;
        const wrapper = api.registry.createType("ExtrinsicPayload", payload, {
          version: payload.version,
        });
        const qrPayload = qrIsHashed ? blake2AsU8a(wrapper.toU8a(true)) : wrapper.toU8a();
        // cache this submittableExtrinsic
        submittable = {
          tx,
          payload: signerPayload.toPayload(),
        };
        // submittable.tx = tx;
        // submittable.payload = signerPayload.toPayload();
        resolve({
          qrAddress: payload.address,
          qrIsHashed,
          qrPayload: _createFrames(_createSignPayload(payload.address, qrIsHashed ? CMD_HASH : CMD_MORTAL, qrPayload, api.genesisHash))[0],
        });
      })
      .catch((err) => resolve({ error: err.message }));
  });
}
Example #17
Source File: test-assets-sufficients.ts    From moonbeam with GNU General Public License v3.0 5 votes vote down vote up
async function mockAssetBalance(
  context,
  assetBalance,
  assetDetails,
  sudoAccount,
  assetId,
  account,
  is_sufficient
) {
  // Register the asset
  await context.polkadotApi.tx.sudo
    .sudo(
      context.polkadotApi.tx.assetManager.registerForeignAsset(
        sourceLocationRelayAssetType,
        relayAssetMetadata,
        new BN(1),
        is_sufficient
      )
    )
    .signAndSend(sudoAccount);
  await context.createBlock();

  let assets = (
    (await context.polkadotApi.query.assetManager.assetIdType(assetId)) as any
  ).toJSON();
  // make sure we created it
  expect(assets["xcm"]["parents"]).to.equal(1);

  // Get keys to modify balance
  let module = xxhashAsU8a(new TextEncoder().encode("Assets"), 128);
  let account_key = xxhashAsU8a(new TextEncoder().encode("Account"), 128);
  let blake2concatAssetId = new Uint8Array([
    ...blake2AsU8a(assetId.toU8a(), 128),
    ...assetId.toU8a(),
  ]);

  let blake2concatAccount = new Uint8Array([
    ...blake2AsU8a(hexToU8a(account), 128),
    ...hexToU8a(account),
  ]);
  let overallAccountKey = new Uint8Array([
    ...module,
    ...account_key,
    ...blake2concatAssetId,
    ...blake2concatAccount,
  ]);

  // Get keys to modify total supply
  let assetKey = xxhashAsU8a(new TextEncoder().encode("Asset"), 128);
  let overallAssetKey = new Uint8Array([...module, ...assetKey, ...blake2concatAssetId]);
  await context.polkadotApi.tx.sudo
    .sudo(
      context.polkadotApi.tx.system.setStorage([
        [u8aToHex(overallAccountKey), u8aToHex(assetBalance.toU8a())],
        [u8aToHex(overallAssetKey), u8aToHex(assetDetails.toU8a())],
      ])
    )
    .signAndSend(sudoAccount);
  await context.createBlock();
  return;
}
Example #18
Source File: index.ts    From parity-bridges-ui with GNU General Public License v3.0 5 votes vote down vote up
export async function getTransactionCallWeight({
  action,
  account,
  targetApi,
  transactionState
}: TransactionCallWeightInput) {
  let weight: number = 0;
  let call: Uint8Array | null = null;
  const { receiverAddress, transferAmount, remarkInput, customCallInput, weightInput } = transactionState;

  if (account) {
    switch (action) {
      case TransactionTypes.REMARK:
        call = (await targetApi.tx.system.remark(remarkInput)).toU8a();
        // TODO [#121] Figure out what the extra bytes are about
        logger.info(`system::remark: ${u8aToHex(call)}`);
        weight = (await targetApi.tx.system.remark(remarkInput).paymentInfo(account)).weight.toNumber();
        break;
      case TransactionTypes.TRANSFER:
        if (receiverAddress) {
          call = (await targetApi.tx.balances.transfer(receiverAddress, transferAmount || 0)).toU8a();
          // TODO [#121] Figure out what the extra bytes are about
          logger.info(`balances::transfer: ${u8aToHex(call)}`);
          logger.info(`after balances::transfer: ${u8aToHex(call)}`);
          weight = (
            await targetApi.tx.balances.transfer(receiverAddress, transferAmount || 0).paymentInfo(account)
          ).weight.toNumber();
        }
        break;
      case TransactionTypes.CUSTOM:
        if (customCallInput) {
          call = isHex(customCallInput) ? hexToU8a(customCallInput.toString()) : null;
          weight = parseInt(weightInput!);
        }
        break;
      default:
        throw new Error(`Unknown type: ${action}`);
    }
  }
  return { call, weight };
}
Example #19
Source File: Keyring.ts    From gear-js with GNU General Public License v3.0 5 votes vote down vote up
static async fromSeed(seed: Uint8Array | string, name?: string): Promise<KeyringPair> {
    const keyring = new Keyring({ type: 'sr25519' });
    await waitReady();

    const keypair = isU8a(seed) ? keyring.addFromSeed(seed, { name }) : keyring.addFromSeed(hexToU8a(seed), { name });
    return keypair;
  }
Example #20
Source File: test-precompile-local-assets-erc20.ts    From moonbeam with GNU General Public License v3.0 5 votes vote down vote up
describeDevMoonbeamAllEthTxTypes(
  "Precompiles - Assets-ERC20 Wasm",
  (context) => {
    let sudoAccount, baltatharAccount, assetId, iFace, assetAddress;
    before("Setup contract and mock balance", async () => {
      const keyring = new Keyring({ type: "ethereum" });
      sudoAccount = await keyring.addFromUri(ALITH_PRIV_KEY, null, "ethereum");
      baltatharAccount = await keyring.addFromUri(BALTATHAR_PRIV_KEY, null, "ethereum");

      // registerAsset
      const { events: eventsRegister } = await createBlockWithExtrinsic(
        context,
        sudoAccount,
        context.polkadotApi.tx.sudo.sudo(
          context.polkadotApi.tx.assetManager.registerLocalAsset(
            baltatharAccount.address,
            baltatharAccount.address,
            true,
            new BN(1)
          )
        )
      );

      // Look for assetId in events
      eventsRegister.forEach((e) => {
        if (e.section.toString() === "assetManager") {
          assetId = e.data[0].toHex();
        }
      });
      assetId = assetId.replace(/,/g, "");

      assetAddress = u8aToHex(new Uint8Array([...hexToU8a("0xFFFFFFFE"), ...hexToU8a(assetId)]));

      const contractData = await getCompiled("LocalAssetExtendedErc20Instance");
      iFace = new ethers.utils.Interface(contractData.contract.abi);
      const { contract, rawTx } = await createContract(context, "LocalAssetExtendedErc20Instance");
      const address = contract.options.address;
      await context.createBlock({ transactions: [rawTx] });
    });
    it("allows to set team", async function () {
      let data = iFace.encodeFunctionData(
        // action
        "set_team",
        [ALITH, ALITH, ALITH]
      );

      const tx = await createTransaction(context, {
        from: BALTATHAR,
        privateKey: BALTATHAR_PRIV_KEY,
        value: "0x0",
        gas: "0x200000",
        gasPrice: GAS_PRICE,
        to: assetAddress,
        data: 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 registeredAsset = (
        (await context.polkadotApi.query.localAssets.asset(assetId)) as any
      ).unwrap();

      expect(registeredAsset.admin.toHex()).to.eq(ALITH.toLowerCase());
      expect(registeredAsset.freezer.toHex()).to.eq(ALITH.toLowerCase());
      expect(registeredAsset.issuer.toHex()).to.eq(ALITH.toLowerCase());
    });
  },
  true
);
Example #21
Source File: Hash.tsx    From crust-apps with Apache License 2.0 5 votes vote down vote up
function Hash (): React.ReactElement {
  const { t } = useTranslation();
  const [{ data, hash, isHexData }, setState] = useState<State>({
    data: '',
    hash: blake2AsHex(stringToU8a(''), 256),
    isHexData: false
  });

  const _onChangeData = useCallback(
    (data: string): void => {
      const isHexData = isHex(data);

      setState({
        data,
        hash: blake2AsHex(
          isHexData
            ? hexToU8a(data)
            : stringToU8a(data),
          256
        ),
        isHexData
      });
    },
    []
  );

  return (
    <div className='toolbox--Hash'>
      <div className='ui--row'>
        <Input
          autoFocus
          className='full'
          help={t<string>('The input data to hash. This can be either specified as a hex value (0x-prefix) or as a string.')}
          label={t<string>('from the following data')}
          onChange={_onChangeData}
          value={data}
        />
      </div>
      <div className='ui--row'>
        <Static
          className='medium'
          help={t<string>('Detection on the input string to determine if it is hex or non-hex.')}
          label={t<string>('hex input data')}
          value={
            isHexData
              ? t<string>('Yes')
              : t<string>('No')
          }
        />
      </div>
      <div className='ui--row'>
        <Output
          className='full'
          help={t<string>('The blake2b 256-bit hash of the actual input data.')}
          isHidden={hash.length === 0}
          isMonospace
          label={t<string>('the resulting hash is')}
          value={hash}
          withCopy
        />
      </div>
    </div>
  );
}
Example #22
Source File: test-precompile-xcm-transactor.ts    From moonbeam with GNU General Public License v3.0 5 votes vote down vote up
async function mockAssetBalance(context, assetBalance, assetDetails, sudoAccount, assetId) {
  // Register the asset
  await context.polkadotApi.tx.sudo
    .sudo(
      context.polkadotApi.tx.assetManager.registerForeignAsset(
        sourceLocationRelayAssetType,
        relayAssetMetadata,
        new BN(1),
        true
      )
    )
    .signAndSend(sudoAccount);
  await context.createBlock();

  let assets = (
    (await context.polkadotApi.query.assetManager.assetIdType(assetId)) as any
  ).toJSON();
  // make sure we created it
  expect(assets["xcm"]["parents"]).to.equal(1);

  // Get keys to modify balance
  let module = xxhashAsU8a(new TextEncoder().encode("Assets"), 128);
  let account_key = xxhashAsU8a(new TextEncoder().encode("Account"), 128);
  let blake2concatAssetId = new Uint8Array([
    ...blake2AsU8a(assetId.toU8a(), 128),
    ...assetId.toU8a(),
  ]);
  let blake2concatAccount = new Uint8Array([
    ...blake2AsU8a(hexToU8a(ALITH), 128),
    ...hexToU8a(ALITH),
  ]);
  let overallAccountKey = new Uint8Array([
    ...module,
    ...account_key,
    ...blake2concatAssetId,
    ...blake2concatAccount,
  ]);

  // Get keys to modify total supply
  let assetKey = xxhashAsU8a(new TextEncoder().encode("Asset"), 128);
  let overallAssetKey = new Uint8Array([...module, ...assetKey, ...blake2concatAssetId]);

  await context.polkadotApi.tx.sudo
    .sudo(
      context.polkadotApi.tx.system.setStorage([
        [u8aToHex(overallAccountKey), u8aToHex(assetBalance.toU8a())],
        [u8aToHex(overallAssetKey), u8aToHex(assetDetails.toU8a())],
      ])
    )
    .signAndSend(sudoAccount);
  await context.createBlock();
  return;
}
Example #23
Source File: Create.tsx    From crust-apps with Apache License 2.0 4 votes vote down vote up
function Create ({ onClose, onStatusChange }: Props): React.ReactElement<Props> {
  const { t } = useTranslation();
  const { api, isEthereum } = useApi();
  const [{ isNameValid, name }, setName] = useState<NameState>({ isNameValid: false, name: '' });
  const [{ address, addressInput, isAddressExisting, isAddressValid }, setAddress] = useState<AddrState>({ address: '', addressInput: '', isAddressExisting: false, isAddressValid: false, isPublicKey: false });
  const info = useCall<DeriveAccountInfo>(!!address && isAddressValid && api.derive.accounts.info, [address]);
  const isValid = (isAddressValid && isNameValid) && !!info?.accountId;

  const _onChangeAddress = useCallback(
    (addressInput: string): void => {
      let address = '';
      let isAddressValid = true;
      let isAddressExisting = false;
      let isPublicKey = false;

      try {
        if (isEthereum) {
          const rawAddress = hexToU8a(addressInput);

          address = ethereumEncode(rawAddress);
          isPublicKey = rawAddress.length === 20;
        } else {
          const publicKey = keyring.decodeAddress(addressInput);

          address = keyring.encodeAddress(publicKey);
          isPublicKey = publicKey.length === 32;
        }

        if (!isAddressValid) {
          const old = keyring.getAddress(address);

          if (old) {
            const newName = old.meta.name || name;

            isAddressExisting = true;
            isAddressValid = true;

            setName({ isNameValid: !!(newName || '').trim(), name: newName });
          }
        }
      } catch (error) {
        isAddressValid = false;
      }

      setAddress({ address: isAddressValid ? address : '', addressInput, isAddressExisting, isAddressValid, isPublicKey });
    },
    [isEthereum, name]
  );

  const _onChangeName = useCallback(
    (name: string) => setName({ isNameValid: !!name.trim(), name }),
    []
  );

  const _onCommit = useCallback(
    (): void => {
      const status = { action: 'create' } as ActionStatus;

      if (!isValid || !info?.accountId) {
        return;
      }

      try {
        const address = info.accountId.toString();

        keyring.saveAddress(address, { genesisHash: keyring.genesisHash, name: name.trim(), tags: [] });

        status.account = address;
        status.status = address ? 'success' : 'error';
        status.message = isAddressExisting
          ? t<string>('address edited')
          : t<string>('address created');

        InputAddress.setLastValue('address', address);
      } catch (error) {
        status.status = 'error';
        status.message = (error as Error).message;
      }

      onStatusChange(status);
      onClose();
    },
    [info, isAddressExisting, isValid, name, onClose, onStatusChange, t]
  );

  return (
    <Modal header={t<string>('Add an address')}>
      <Modal.Content>
        <AddressRow
          defaultName={name}
          noDefaultNameOpacity
          value={
            isAddressValid
              ? info?.accountId?.toString()
              : undefined
          }
        >
          <Input
            autoFocus
            className='full'
            help={t<string>('Paste here the address of the contact you want to add to your address book.')}
            isError={!isAddressValid}
            label={t<string>('address')}
            onChange={_onChangeAddress}
            onEnter={_onCommit}
            placeholder={t<string>('new address')}
            value={addressInput}
          />
          <Input
            className='full'
            help={t<string>('Type the name of your contact. This name will be used across all the apps. It can be edited later on.')}
            isError={!isNameValid}
            label={t<string>('name')}
            onChange={_onChangeName}
            onEnter={_onCommit}
            value={name}
          />
        </AddressRow>
      </Modal.Content>
      <Modal.Actions onCancel={onClose}>
        <Button
          icon='save'
          isDisabled={!isValid}
          label={t<string>('Save')}
          onClick={_onCommit}
        />
      </Modal.Actions>
    </Modal>
  );
}
Example #24
Source File: QrSigner.ts    From sdk with Apache License 2.0 4 votes vote down vote up
async function _constructDataFromBytes(bytes: Uint8Array, multipartComplete = false) {
  const frameInfo = hexStripPrefix(u8aToHex(bytes.slice(0, 5)));
  const frameCount = parseInt(frameInfo.substr(2, 4), 16);
  const isMultipart = frameCount > 1; // for simplicity, even single frame payloads are marked as multipart.
  const currentFrame = parseInt(frameInfo.substr(6, 4), 16);
  const uosAfterFrames = hexStripPrefix(u8aToHex(bytes.slice(5)));

  // UOS after frames can be metadata json
  if (isMultipart && !multipartComplete) {
    const partData = {
      currentFrame,
      frameCount,
      isMultipart,
      partData: uosAfterFrames,
    };
    return partData;
  }

  const zerothByte = uosAfterFrames.substr(0, 2);
  const firstByte = uosAfterFrames.substr(2, 2);
  const secondByte = uosAfterFrames.substr(4, 2);

  let action: string;

  try {
    // decode payload appropriately via UOS
    switch (zerothByte) {
      case "45": {
        // Ethereum UOS payload
        const data = {
          data: {}, // for consistency with legacy data format.
        };
        action = firstByte === "00" || firstByte === "01" ? "signData" : firstByte === "01" ? "signTransaction" : null;
        const address = uosAfterFrames.substr(4, 44);

        data["action"] = action;
        data.data["account"] = address;
        if (action === "signData") {
          data.data["rlp"] = uosAfterFrames[13];
        } else if (action === "signTransaction") {
          data.data["data"] = uosAfterFrames[13];
        } else {
          throw new Error("Could not determine action type.");
        }
        return data;
      }
      case "53": {
        // Substrate UOS payload
        const data = {
          data: {}, // for consistency with legacy data format.
        };
        try {
          data.data["crypto"] = firstByte === "00" ? "ed25519" : firstByte === "01" ? "sr25519" : null;
          const pubKeyHex = uosAfterFrames.substr(6, 64);
          const publicKeyAsBytes = hexToU8a("0x" + pubKeyHex);
          const hexEncodedData = "0x" + uosAfterFrames.slice(70);
          const hexPayload = hexEncodedData.slice(0, -64);
          const genesisHash = `0x${hexEncodedData.substr(-64)}`;
          const rawPayload = hexToU8a(hexPayload);
          data.data["genesisHash"] = genesisHash;
          const isOversized = rawPayload.length > 256;
          const network = SUBSTRATE_NETWORK_LIST[genesisHash];
          // if (!network) {
          //   throw new Error(`Signer does not currently support a chain with genesis hash: ${genesisHash}`);
          // }

          switch (secondByte) {
            case "00": // sign mortal extrinsic
            case "02": // sign immortal extrinsic
              data["action"] = isOversized ? "signData" : "signTransaction";
              data["oversized"] = isOversized;
              data["isHash"] = isOversized;
              const [offset] = compactFromU8a(rawPayload);
              const payload = rawPayload.subarray(offset);
              // data.data.data = isOversized
              // 	? await blake2b(u8aToHex(payload, -1, false))
              // 	: rawPayload;
              data.data["data"] = rawPayload; // ignore oversized data for now
              data.data["account"] = encodeAddress(publicKeyAsBytes, network?.prefix || 0); // encode to the prefix;

              break;
            case "01": // data is a hash
              data["action"] = "signData";
              data["oversized"] = false;
              data["isHash"] = true;
              data.data["data"] = hexPayload;
              data.data["account"] = encodeAddress(publicKeyAsBytes, network?.prefix || 0); // default to Kusama
              break;
          }
        } catch (e) {
          throw new Error("Error: something went wrong decoding the Substrate UOS payload: " + uosAfterFrames);
        }
        return data;
      }
      default:
        throw new Error("Error: Payload is not formatted correctly: " + bytes);
    }
  } catch (e) {
    throw new Error("we cannot handle the payload: " + bytes);
  }
}
Example #25
Source File: index.tsx    From crust-apps with Apache License 2.0 4 votes vote down vote up
function Claims(): React.ReactElement<Props> {
  const [didCopy, setDidCopy] = useState(false);
  const [ethereumAddress, setEthereumAddress] = useState<string | undefined | null>(null);
  const [signature, setSignature] = useState<EcdsaSignature | null>(null);
  const [step, setStep] = useState<Step>(Step.Account);
  const [accountId, setAccountId] = useState<string | null>(null);
  const { api, systemChain } = useApi();
  const { t } = useTranslation();
  const [statusOpen, setStatusOpen] = useState<boolean>(false);
  const [result, setResult] = useState<string>('');
  const [status, setStatus] = useState<string>('');
  const [ethereumTxHashValid, setEthereumTxHashValid] = useState<boolean>(false);
  const [isBusy, setIsBusy] = useState<boolean>(false);
  const [isValid, setIsValid] = useState(false);
  const [ethereumTxHash, setEthereumTxHash] = useState<string | undefined | null>(null);

  // This preclaimEthereumAddress holds the result of `api.query.claims.preclaims`:
  // - an `EthereumAddress` when there's a preclaim
  // - null if no preclaim
  // - `PRECLAIMS_LOADING` if we're fetching the results
  const [preclaimEthereumAddress, setPreclaimEthereumAddress] = useState<string | null | undefined | typeof PRECLAIMS_LOADING>(PRECLAIMS_LOADING);
  const isPreclaimed = !!preclaimEthereumAddress && preclaimEthereumAddress !== PRECLAIMS_LOADING;
  const claimLimit = useCall<BalanceOf>(api.query.claims.claimLimit);

  // Everytime we change account, reset everything, and check if the accountId
  // has a preclaim.
  useEffect(() => {
    if (!accountId) {
      return;
    }

    setStep(Step.Account);
    setEthereumAddress(null);
    setEthereumTxHash(null);
    setPreclaimEthereumAddress(PRECLAIMS_LOADING);

    if (!api.query.claims || !api.query.claims.preclaims) {
      return setPreclaimEthereumAddress(null);
    }

    api.query.claims
      .preclaims<Option<EthereumAddress>>(accountId)
      .then((preclaim): void => {
        const address = preclaim.unwrapOr(null)?.toString();

        setEthereumAddress(address);
        setPreclaimEthereumAddress(address);
      })
      .catch((): void => setPreclaimEthereumAddress(null));
  }, [accountId, api.query.claims, api.query.claims.preclaims]);

  // Old claim process used `api.tx.claims.claim`, and didn't have attest
  const isOldClaimProcess = !api.tx.claims.claimAttest;

  useEffect(() => {
    if (didCopy) {
      setTimeout((): void => {
        setDidCopy(false);
      }, 1000);
    }
  }, [didCopy]);

  const goToStepAccount = useCallback(() => {
    setStep(Step.Account);
    setEthereumTxHash("");
    setEthereumTxHashValid(false);
  }, []);

  const goToStepSign = useCallback(() => {
    setStep(Step.Sign);
  }, []);

  const goToStepClaim = useCallback(() => {
    setStep(Step.Claim);
  }, []);

  const handleAccountStep = useCallback(async () => {
    setIsBusy(true);

    api.query.claims
      .claimed<Option<BalanceOf>>(ethereumTxHash?.toString())
      .then(async (claim): Promise<void> => {
        const isClaimed = JSON.parse(JSON.stringify(claim));

        if (isClaimed) {
          setResult('AlreadyClaimed');
          setStatus('error');
          setStatusOpen(true);
        } else {
          const result = await httpPost("https://claim.crust.network/claim/" + ethereumTxHash);
          setIsBusy(false);
          setResult(result.statusText);
          setStatus(result.status);

          if (result.code == 200) {
            setEthereumTxHashValid(true);
            goToStepSign();
          } else {
            api.query.claims
              .claims<Option<BalanceOf>>(ethereumTxHash?.toString())
              .then(async (claim): Promise<void> => {
                const claimOpt = JSON.parse(JSON.stringify(claim));
                if (claimOpt) {
                  setResult('MintClaimSuccess');
                  setStatus('success');
                  setEthereumTxHashValid(true);
                  goToStepSign();
                } else {
                  setResult('MintError, Please try again');
                  setStatus('error');
                }
              })
              .catch((): void => setIsBusy(false));
          }
          setStatusOpen(true);
        }
      })
      .catch((): void => setIsBusy(false))
      .finally(() =>  setIsBusy(false));
  }, [ethereumAddress, goToStepClaim, goToStepSign, isPreclaimed, isOldClaimProcess, ethereumTxHash]);

  const onChangeEthereumTxHash = useCallback((hex: string) => {
    let [isValid, value] = convertInput(hex);

    isValid = isValid && (
      length !== -1
        ? value.length === 32
        : value.length !== 0
    );
    setIsValid(isValid);
    setEthereumTxHash(hex.trim());
  }, [ethereumTxHash]);

  function convertInput(value: string): [boolean, Uint8Array] {
    if (value === '0x') {
      return [true, new Uint8Array([])];
    } else if (value.startsWith('0x')) {
      try {
        return [true, hexToU8a(value)];
      } catch (error) {
        return [false, new Uint8Array([])];
      }
    }

    // maybe it is an ss58?
    try {
      return [true, decodeAddress(value)];
    } catch (error) {
      // we continue
    }

    return isAscii(value)
      ? [true, stringToU8a(value)]
      : [value === '0x', new Uint8Array([])];
  }

  // Depending on the account, decide which step to show.
  // const handleAccountStep = useCallback(() => {
  //   if (isPreclaimed) {
  //     goToStepClaim();
  //   } else if (ethereumAddress || isOldClaimProcess) {
  //     goToStepSign();
  //   } else {
  //     setStep(Step.ETHAddress);
  //   }
  // }, [ethereumAddress, goToStepClaim, goToStepSign, isPreclaimed, isOldClaimProcess]);

  const onChangeSignature = useCallback((event: React.SyntheticEvent<Element>) => {
    const { value: signatureJson } = event.target as HTMLInputElement;

    const { ethereumAddress, signature } = recoverFromJSON(signatureJson);

    setEthereumAddress(ethereumAddress?.toString());
    setSignature(signature);
  }, []);

  const onChangeEthereumAddress = useCallback((value: string) => {
    // FIXME We surely need a better check than just a trim

    setEthereumAddress(value.trim());
  }, []);

  const onCopy = useCallback(() => {
    setDidCopy(true);
  }, []);

  // If it's 1/ not preclaimed and 2/ not the old claiming process, fetch the
  // statement kind to sign.
  const statementKind = useCall<StatementKind | null>(!isPreclaimed && !isOldClaimProcess && !!ethereumAddress && api.query.claims.signing, [ethereumAddress], transformStatement);

  const statementSentence = getStatement(systemChain, statementKind)?.sentence || '';

  const prefix = u8aToString(api.consts.claims.prefix.toU8a(true));
  const payload = accountId
    ? `${prefix}${u8aToHex(decodeAddress(accountId), -1, false)}${statementSentence}${ethereumTxHash?.substring(2)}`
    : '';

  return (
    <main>
      {!isOldClaimProcess && <Warning />}
      <h2>
        {t<string>('Claim your {{token}} tokens', {
          replace: {
            token: TokenUnit.abbr
          }
        })}
      </h2>
      <Columar>
        <Columar.Column>
          <Card withBottomMargin>
            <h3>{t<string>('0. Burn your ')}<a href='https://etherscan.io/token/0x32a7C02e79c4ea1008dD6564b35F131428673c41'>{t('ERC20 CRU')}</a>{t<string>(', transfer to address ')} <a href='https://etherscan.io/address/0x0000000000000000000000000000000000000001' target="_blank">0x0000000000000000000000000000000000000001</a></h3>
            <Banner type='warning'>
              <p>{t<string>('Please make sure you have the authority to make signature with the private key of the wallet account, using an exchange account to sent a transfer (withdrawal) transaction will be invalidated and cause asset loss, you are responsible for the consequences')}</p>
            </Banner>
            <img style={{'marginLeft': 'auto', 'marginRight': 'auto', 'display': 'block', "width": "150px" }} src={burnPng as string} />
          </Card>
          {(<Card withBottomMargin>
            <h3>{t<string>(`1. Select your {{chain}} account and enter`, {
              replace: {
                chain: systemChain
              }
            })} <a href='https://etherscan.io/token/0x32a7C02e79c4ea1008dD6564b35F131428673c41'>{t('ERC20 CRU')}</a>
             {t<string>(' transfer tx hash')}<span>
               {t<string>(`, If your claim amount is greater than the claim limit `)}
               <span style={{ 'color': '#ff8812', 'textDecoration': 'underline', 'fontStyle': 'italic' }}>({formatBalance(claimLimit, { withUnit: 'CRU' })})</span>
               {t<string>(', please wait for the limit update')}
               </span>
            </h3>
            <InputAddress
              defaultValue={accountId}
              help={t<string>('The account you want to claim to.')}
              isDisabled={ethereumTxHashValid}
              label={t<string>('claim to account')}
              onChange={setAccountId}
              type='account'
            />
            <Input
              autoFocus
              className='full'
              help={t<string>('The Ethereum CRU transfer tx hash (starting by "0x")')}
              isDisabled={ethereumTxHashValid}
              isError={!isValid}
              label={t<string>('Ethereum tx hash')}
              onChange={onChangeEthereumTxHash}
              placeholder={t<string>('0x prefixed hex, e.g. 0x1234 or ascii data')}
              value={ethereumTxHash || ''}
            />
            {(step === Step.Account) && (<Button.Group>
              <Button
                icon='sign-in-alt'
                isBusy={isBusy}
                isDisabled={preclaimEthereumAddress === PRECLAIMS_LOADING || ethereumTxHash === null || ethereumTxHash === '' || !isValid}
                label={preclaimEthereumAddress === PRECLAIMS_LOADING
                  ? t<string>('Loading')
                  : t<string>('Continue')
                }
                onClick={handleAccountStep}
              />
            </Button.Group>)}
            <HttpStatus
              isStatusOpen={statusOpen}
              message={result}
              setStatusOpen={setStatusOpen}
              status={status}
            />
          </Card>)}
          {
            // We need to know the ethereuem address only for the new process
            // to be able to know the statement kind so that the users can sign it
            (step >= Step.ETHAddress && !isPreclaimed && !isOldClaimProcess) && (
              <Card withBottomMargin>
                <h3>{t<string>('2. Enter the ETH address from the sale.')}</h3>
                <Input
                  autoFocus
                  className='full'
                  help={t<string>('The the Ethereum address you burnt your ERC20 CRU in step 0 (starting by "0x")')}
                  label={t<string>('Pre-sale ethereum address')}
                  onChange={onChangeEthereumAddress}
                  value={ethereumAddress || ''}
                />
                {(step === Step.ETHAddress) && (
                  <Button.Group>
                    <Button
                      icon='sign-in-alt'
                      isDisabled={!ethereumAddress}
                      label={t<string>('Continue')}
                      onClick={goToStepSign}
                    />
                  </Button.Group>
                )}
              </Card>
            )}
            {(step >= Step.Sign && !isPreclaimed) && (
              <Card>
                <h3>{t<string>('{{step}}. Sign with your ETH address', { replace: { step: isOldClaimProcess ? '2' : '3' } })}</h3>
                {!isOldClaimProcess && (
                  <Statement
                    kind={statementKind}
                    systemChain={systemChain}
                  />
                )}
                <div>{t<string>('Copy the following string and sign it with the Ethereum account you burnt your ERC20 CRU in step 0, using the string as the payload, and then paste the transaction signature object below:')}</div>
                <CopyToClipboard
                  onCopy={onCopy}
                  text={payload}
                >
                  <Payload
                    data-for='tx-payload'
                    data-tip
                  >
                    {payload}
                  </Payload>
                </CopyToClipboard>
                <Tooltip
                  place='right'
                  text={didCopy ? t<string>('copied') : t<string>('click to copy')}
                  trigger='tx-payload'
                />
                <div>{t<string>('Paste the signed message into the field below. The placeholder text is there as a hint to what the message should look like:')}</div>
                <Signature
                  onChange={onChangeSignature}
                  placeholder={`{\n  "address": "0x ...",\n  "msg": "0x ...",\n  "sig": "...",\n  "version": "3",\n  "signer": "..."\n}`}
                  rows={10}
                />
                {(step === Step.Sign) && (
                  <Button.Group>
                    <Button
                      icon='sign-in-alt'
                      isDisabled={!accountId || !signature}
                      label={t<string>('Confirm claim')}
                      onClick={goToStepClaim}
                    />
                  </Button.Group>
                )}
              </Card>
            )}
        </Columar.Column>
        <Columar.Column>
            {(step >= Step.Claim) && (
              isPreclaimed
                ? <AttestDisplay
                  accountId={accountId}
                  ethereumAddress={ethereumAddress}
                  onSuccess={goToStepAccount}
                  statementKind={statementKind}
                  systemChain={systemChain}
                />
                : <ClaimDisplay
                  accountId={accountId}
                  ethereumAddress={ethereumAddress}
                  ethereumSignature={signature}
                  isOldClaimProcess={isOldClaimProcess}
                  onSuccess={goToStepAccount}
                  statementKind={statementKind}
                  ethereumTxHash={ethereumTxHash}
                />
            )}
        </Columar.Column>
      </Columar>
    </main>
  );
}
Example #26
Source File: test-xcm-para.ts    From moonbeam with GNU General Public License v3.0 4 votes vote down vote up
describeParachain(
  "XCM - send_para_a_asset_from_para_b_to_para_c",
  { chain: "moonbase-local", numberOfParachains: 3 },
  (context) => {
    let keyring: Keyring,
      alith: KeyringPair,
      baltathar: KeyringPair,
      parachainOne: ApiPromise,
      parachainTwo: ApiPromise,
      parachainThree: ApiPromise,
      relayOne: ApiPromise,
      assetId: string,
      sourceLocationParaA: SourceLocation,
      initialBalance: number;
    before("First send relay chain asset to parachain", async function () {
      keyring = new Keyring({ type: "ethereum" });

      // Setup Relaychain
      relayOne = context._polkadotApiRelaychains[0];

      // Setup Parachains
      alith = await keyring.addFromUri(ALITH_PRIV_KEY, null, "ethereum");
      baltathar = await keyring.addFromUri(BALTATHAR_PRIV_KEY, null, "ethereum");
      parachainOne = context.polkadotApiParaone;
      parachainTwo = context._polkadotApiParachains[1].apis[0];
      parachainThree = context._polkadotApiParachains[2].apis[0];

      // Log events
      logEvents(parachainOne, "PARA A");
      logEvents(parachainTwo, "PARA B");
      logEvents(parachainThree, "PARA C");
      logEvents(relayOne, "RELAY");

      initialBalance = Number(
        ((await parachainOne.query.system.account(BALTATHAR)) as any).data.free
      );

      // Get Pallet balances index
      const metadata = await parachainOne.rpc.state.getMetadata();
      const palletIndex = (metadata.asLatest.toHuman().pallets as Array<any>).find((pallet) => {
        return pallet.name === "Balances";
      }).index;

      expect(palletIndex);

      sourceLocationParaA = {
        XCM: {
          parents: new BN(1),
          interior: { X2: [{ Parachain: new BN(1000) }, { Palletinstance: new BN(palletIndex) }] },
        },
      };

      // PARACHAIN B
      // registerAsset
      ({ assetId } = await registerAssetToParachain(
        parachainTwo,
        alith,
        sourceLocationParaA,
        paraAssetMetadata
      ));

      // PARACHAIN C
      // registerAsset
      await registerAssetToParachain(parachainThree, alith, sourceLocationParaA, paraAssetMetadata);
    });
    it("should be able to receive an asset back in para a from para b", async function () {
      // PARACHAIN A
      // transfer 100 units to parachain B
      await createBlockWithExtrinsicParachain(
        parachainOne,
        baltathar,
        parachainOne.tx.xTokens.transfer(
          "SelfReserve",
          HUNDRED_UNITS_PARA,
          {
            V1: {
              parents: new BN(1),
              interior: {
                X2: [
                  { Parachain: new BN(2000) },
                  { AccountKey20: { network: "Any", key: hexToU8a(BALTATHAR) } },
                ],
              },
            },
          },
          new BN(4000000000)
        )
      );

      await waitOneBlock(parachainTwo, 6);

      // PARACHAIN B
      // transfer 100 units to parachain C
      const { events: eventsTransfer2 } = await createBlockWithExtrinsicParachain(
        parachainTwo,
        baltathar,
        parachainTwo.tx.xTokens.transfer(
          { OtherReserve: assetId },
          HUNDRED_UNITS_PARA,
          {
            V1: {
              parents: new BN(1),
              interior: {
                X2: [
                  { Parachain: new BN(3000) },
                  { AccountKey20: { network: "Any", key: hexToU8a(BALTATHAR) } },
                ],
              },
            },
          },
          new BN(4000000000)
        )
      );

      expect(eventsTransfer2[2].toHuman().method).to.eq("XcmpMessageSent");
      expect(eventsTransfer2[3].toHuman().method).to.eq("Transferred");
      expect(eventsTransfer2[8].toHuman().method).to.eq("ExtrinsicSuccess");

      await waitOneBlock(parachainThree, 3);
      // Verify that difference is 100 units plus fees (less than 1% of 10^18)
      const targetBalance: number = Number(BigInt(BigInt(initialBalance) - HUNDRED_UNITS_PARA));
      let expectedBaltatharParaTwoBalance = BigInt(0);
      let paraAXcmFee = BigInt(400000000);
      const diff =
        Number(((await parachainOne.query.system.account(BALTATHAR)) as any).data.free) -
        targetBalance;
      expect(diff < 10000000000000000).to.eq(true);
      expect(
        ((await parachainTwo.query.assets.account(assetId, BALTATHAR)) as any).balance.toString()
      ).to.eq(expectedBaltatharParaTwoBalance.toString());
      expect(
        ((await parachainThree.query.assets.account(assetId, BALTATHAR)) as any).balance.toString()
      ).to.eq((BigInt(HUNDRED_UNITS_PARA) - paraAXcmFee).toString());
    });
  }
);
Example #27
Source File: getBlock.test.ts    From metamask-snap-polkadot with Apache License 2.0 4 votes vote down vote up
describe('Test rpc handler function: getBlock', function() {

  const walletStub = new WalletMock();

  afterEach(function() {
    walletStub.reset();
  });

  it('should return block on block id as number', async function () {
    // api stub
    const apiStub = {rpc: {chain: {getBlock: sinon.stub(), getBlockHash: sinon.stub()}}};
    apiStub.rpc.chain.getBlockHash.returns(
      hexToU8a("0xc9fb400866641ca80ef3e760d904fe15a8c9eda6ff1bd769b0628e26e82d5c75") as BlockHash
    );
    // eslint-disable-next-line max-len
    apiStub.rpc.chain.getBlock.returns({block:{hash: {toHex: (): string => "0xc9fb400866641ca80ef3e760d904fe15a8c9eda6ff1bd769b0628e26e82d5c75"}, header: {number: 10}}});
    const api = apiStub as unknown as ApiPromise;
    const result = await getBlock(1, api);
    expect(result).not.to.be.null;
    expect(result.hash).to.be.eq("0xc9fb400866641ca80ef3e760d904fe15a8c9eda6ff1bd769b0628e26e82d5c75");
    expect(result.number).to.be.eq("10");
    expect(apiStub.rpc.chain.getBlockHash).to.have.been.calledOnceWith(1);
    // eslint-disable-next-line max-len
    expect(apiStub.rpc.chain.getBlock).to.have.been.calledOnceWith(hexToU8a("0xc9fb400866641ca80ef3e760d904fe15a8c9eda6ff1bd769b0628e26e82d5c75") as BlockHash);
  });

  it('should return block on block id as string', async function () {
    // api stub
    const apiStub = {rpc: {chain: {getBlock: sinon.stub(), getBlockHash: sinon.stub()}}};
    apiStub.rpc.chain.getBlockHash.returns(
      hexToU8a("0xc9fb400866641ca80ef3e760d904fe15a8c9eda6ff1bd769b0628e26e82d5c75") as BlockHash
    );
    // eslint-disable-next-line max-len
    apiStub.rpc.chain.getBlock.returns({block:{hash: {toHex: (): string => "0xc9fb400866641ca80ef3e760d904fe15a8c9eda6ff1bd769b0628e26e82d5c75"}, header: {number: 10}}});
    const api = apiStub as unknown as ApiPromise;
    const result = await getBlock("1", api);
    expect(result).not.to.be.null;
    expect(result.hash).to.be.eq("0xc9fb400866641ca80ef3e760d904fe15a8c9eda6ff1bd769b0628e26e82d5c75");
    expect(result.number).to.be.eq("10");
    expect(apiStub.rpc.chain.getBlockHash).to.have.been.calledOnceWith(1);
    // eslint-disable-next-line max-len
    expect(apiStub.rpc.chain.getBlock).to.have.been.calledOnceWith(hexToU8a("0xc9fb400866641ca80ef3e760d904fe15a8c9eda6ff1bd769b0628e26e82d5c75") as BlockHash);
  });

  it('should return block on block hash as string', async function () {
    // api stub
    const apiStub = {rpc: {chain: {getBlock: sinon.stub()}}};
    apiStub.rpc.chain.getBlock.returns({});
    // eslint-disable-next-line max-len
    apiStub.rpc.chain.getBlock.returns({block:{hash: {toHex: (): string => "0xc9fb400866641ca80ef3e760d904fe15a8c9eda6ff1bd769b0628e26e82d5c75"}, header: {number: 10}}});
    const api = apiStub as unknown as ApiPromise;
    // eslint-disable-next-line max-len
    const result = await getBlock("0xc9fb400866641ca80ef3e760d904fe15a8c9eda6ff1bd769b0628e26e82d5c75", api);
    expect(result).not.to.be.null;
    expect(result.hash).to.be.eq("0xc9fb400866641ca80ef3e760d904fe15a8c9eda6ff1bd769b0628e26e82d5c75");
    expect(result.number).to.be.eq("10");
    // eslint-disable-next-line max-len
    expect(apiStub.rpc.chain.getBlock).to.have.been.calledOnceWith("0xc9fb400866641ca80ef3e760d904fe15a8c9eda6ff1bd769b0628e26e82d5c75");
  });

  it('should return latest block on "latest" as parameter', async function () {
    // api stub
    const apiStub = {rpc: {chain: {getBlock: sinon.stub(), getHeader: sinon.stub()}}};
    apiStub.rpc.chain.getBlock.returns({});
    // eslint-disable-next-line max-len
    apiStub.rpc.chain.getBlock.returns({block:{hash: {toHex: (): string => "0xc9fb400866641ca80ef3e760d904fe15a8c9eda6ff1bd769b0628e26e82d5c75"}, header: {number: 10}}});
    // eslint-disable-next-line max-len
    apiStub.rpc.chain.getHeader.returns({hash: hexToU8a("0xc9fb400866641ca80ef3e760d904fe15a8c9eda6ff1bd769b0628e26e82d5c75") as H256});
    const api = apiStub as unknown as ApiPromise;
    const result = await getBlock("latest", api);
    expect(result).not.to.be.null;
    expect(result.hash).to.be.eq("0xc9fb400866641ca80ef3e760d904fe15a8c9eda6ff1bd769b0628e26e82d5c75");
    expect(result.number).to.be.eq("10");
    expect(apiStub.rpc.chain.getHeader).to.have.been.calledOnce;
    // eslint-disable-next-line max-len
    expect(apiStub.rpc.chain.getBlock).to.have.been.calledOnceWith(hexToU8a("0xc9fb400866641ca80ef3e760d904fe15a8c9eda6ff1bd769b0628e26e82d5c75") as BlockHash);
  });

  it('should return null on invalid string as parameter', async function () {
    const api = {} as unknown as ApiPromise;
    const result = await getBlock("zz", api);
    expect(result).to.be.null;
  });

  it('should return null on empty parameters object', async function () {
    const api = {} as unknown as ApiPromise;
    const result = await getBlock(null, api);
    expect(result).to.be.null;
  });

});
Example #28
Source File: index.tsx    From crust-apps with Apache License 2.0 4 votes vote down vote up
function CSMClaims (): React.ReactElement<Props> {
  const [didCopy, setDidCopy] = useState(false);
  const [ethereumAddress, setEthereumAddress] = useState<string | undefined | null>(null);
  const [signature, setSignature] = useState<EcdsaSignature | null>(null);
  const [step, setStep] = useState<Step>(Step.Account);
  const [accountId, setAccountId] = useState<string | null>(null);
  const { api, systemChain } = useApi();
  const { t } = useTranslation();
  const [statusOpen, setStatusOpen] = useState<boolean>(false);
  const [result, setResult] = useState<string>('');
  const [status, setStatus] = useState<string>('');
  const [ethereumTxHashValid, setEthereumTxHashValid] = useState<boolean>(false);
  const [isBusy, setIsBusy] = useState<boolean>(false);
  const [isValid, setIsValid] = useState(false);
  const [ethereumTxHash, setEthereumTxHash] = useState<string | undefined | null>(null);
  const csmClaimLimit = useCall<BalanceOf>(api.query.claims.csmClaimLimit);

  // This preclaimEthereumAddress holds the result of `api.query.claims.preclaims`:
  // - an `EthereumAddress` when there's a preclaim
  // - null if no preclaim
  // - `PRECLAIMS_LOADING` if we're fetching the results
  const [preclaimEthereumAddress, setPreclaimEthereumAddress] = useState<string | null | undefined | typeof PRECLAIMS_LOADING>(PRECLAIMS_LOADING);
  const isPreclaimed = !!preclaimEthereumAddress && preclaimEthereumAddress !== PRECLAIMS_LOADING;

  // Everytime we change account, reset everything, and check if the accountId
  // has a preclaim.
  useEffect(() => {
    if (!accountId) {
      return;
    }

    setStep(Step.Account);
    setEthereumAddress(null);
    setEthereumTxHash(null);
    setPreclaimEthereumAddress(PRECLAIMS_LOADING);

    if (!api.query.claims || !api.query.claims.preclaims) {
      return setPreclaimEthereumAddress(null);
    }

    api.query.claims
      .preclaims<Option<EthereumAddress>>(accountId)
      .then((preclaim): void => {
        const address = preclaim.unwrapOr(null)?.toString();

        setEthereumAddress(address);
        setPreclaimEthereumAddress(address);
      })
      .catch((): void => setPreclaimEthereumAddress(null));
  }, [accountId, api.query.claims, api.query.claims.preclaims]);

  // Old claim process used `api.tx.claims.claim`, and didn't have attest
  const isOldClaimProcess = !api.tx.claims.claimAttest;

  useEffect(() => {
    if (didCopy) {
      setTimeout((): void => {
        setDidCopy(false);
      }, 1000);
    }
  }, [didCopy]);

  const goToStepAccount = useCallback(() => {
    setStep(Step.Account);
    setEthereumTxHash("");
    setEthereumTxHashValid(false);
  }, []);

  const goToStepSign = useCallback(() => {
    setStep(Step.Sign);
  }, []);

  const goToStepClaim = useCallback(() => {
    setStep(Step.Claim);
  }, []);

  const handleAccountStep = useCallback(async () => {
    setIsBusy(true);
    const result = await httpPost("https://csm-bridge-api.crust.network/csmClaim/" + ethereumTxHash);

    setIsBusy(false);
    setResult(result.statusText);
    setStatus(result.status);

    if (result.code == 200) {
      setStatusOpen(true);
      setEthereumTxHashValid(true);
      goToStepSign();
    } else {
      api.query.claims
        .csmClaims<Option<BalanceOf>>(ethereumTxHash?.toString())
        .then((claim): void => {
          const claimOpt = JSON.parse(JSON.stringify(claim));

          if (claimOpt) {
            api.query.claims
              .csmClaimed<Option<BalanceOf>>(ethereumTxHash?.toString())
              .then((claimed): void => {
                const isClaimed = JSON.parse(JSON.stringify(claimed));

                if (isClaimed) {
                  setStatusOpen(true);
                } else {
                  setStatusOpen(true);
                  setResult('MintClaimSuccess');
                  setStatus('success');
                  setEthereumTxHashValid(true);
                  goToStepSign();
                }
              });
          } else {
            setStatusOpen(true);
          }
        })
        .catch((): void => setIsBusy(false));
    }
  }, [ethereumAddress, goToStepAccount, goToStepClaim, goToStepSign, isPreclaimed, isOldClaimProcess, ethereumTxHash]);

  const onChangeEthereumTxHash = useCallback((hex: string) => {
    let [isValid, value] = convertInput(hex);

    isValid = isValid && (
      length !== -1
        ? value.length === 32
        : value.length !== 0
    );
    setIsValid(isValid);
    setEthereumTxHash(hex.trim());
  }, [ethereumTxHash]);

  function convertInput (value: string): [boolean, Uint8Array] {
    if (value === '0x') {
      return [true, new Uint8Array([])];
    } else if (value.startsWith('0x')) {
      try {
        return [true, hexToU8a(value)];
      } catch (error) {
        return [false, new Uint8Array([])];
      }
    }

    // maybe it is an ss58?
    try {
      return [true, decodeAddress(value)];
    } catch (error) {
      // we continue
    }

    return isAscii(value)
      ? [true, stringToU8a(value)]
      : [value === '0x', new Uint8Array([])];
  }

  // Depending on the account, decide which step to show.
  // const handleAccountStep = useCallback(() => {
  //   if (isPreclaimed) {
  //     goToStepClaim();
  //   } else if (ethereumAddress || isOldClaimProcess) {
  //     goToStepSign();
  //   } else {
  //     setStep(Step.ETHAddress);
  //   }
  // }, [ethereumAddress, goToStepClaim, goToStepSign, isPreclaimed, isOldClaimProcess]);

  const onChangeSignature = useCallback((event: React.SyntheticEvent<Element>) => {
    const { value: signatureJson } = event.target as HTMLInputElement;

    const { ethereumAddress, signature } = recoverFromJSON(signatureJson);

    setEthereumAddress(ethereumAddress?.toString());
    setSignature(signature);
  }, []);

  const onChangeEthereumAddress = useCallback((value: string) => {
    // FIXME We surely need a better check than just a trim

    setEthereumAddress(value.trim());
  }, []);

  const onCopy = useCallback(() => {
    setDidCopy(true);
  }, []);

  // If it's 1/ not preclaimed and 2/ not the old claiming process, fetch the
  // statement kind to sign.
  const statementKind = useCall<StatementKind | null>(!isPreclaimed && !isOldClaimProcess && !!ethereumAddress && api.query.claims.signing, [ethereumAddress], transformStatement);

  const statementSentence = getStatement(systemChain, statementKind)?.sentence || '';

  // const prefix = u8aToString(api.consts.claims.CsmPrefix.toU8a(true));
  const prefix = 'Pay CSMs to the Crust account:'
  const payload = accountId
    ? `${prefix}${u8aToHex(decodeAddress(accountId), -1, false)}${statementSentence}${ethereumTxHash?.substring(2)}`
    : '';
  
  return (
    <main>
      {!isOldClaimProcess && <Warning />}
      <h1>
        <Trans>Claim your <em>CSM</em> tokens</Trans>
      </h1>
      <Columar>
        <Columar.Column>
          <Card withBottomMargin>
            <h3><span style={{"wordWrap": "break-word", "wordBreak": "break-all"}}>{t<string>(`0. Please make sure you have the authority to make signature with the private key of the wallet account `)}<span style={{ 'fontWeight': 'bold' }}>({t<string>('address: ')}<a href='https://etherscan.io/address/0x17a9037cdfb24ffcc13697d03c3bcd4dff34732b' target="_blank">0x17A9037cdFB24FfcC13697d03C3bcd4DFF34732b</a>)</span><span>{t<string>(', using an exchange account to sent a transfer (withdrawal) transaction will be invalidated and cause asset loss.')}</span> <span style={{ 'fontWeight': 'bold', 'color': 'red' }}>{t<string>(` You are responsible for the consequences!`)}</span></span></h3>
            <img style={{'marginLeft': 'auto', 'marginRight': 'auto', 'display': 'block', "width": "150px" }} src={claimPng as string} />
          </Card>
          {(<Card withBottomMargin>
            <h3>{t<string>(`1. Select your {{chain}} account and enter`, {
                replace: {
                  chain: systemChain
                }
              })} <a href='https://rinkeby.etherscan.io/token/0x7a1c61c526dae21c23b50a490c18d04f8077608f'>{t('ERC20 CSM')}</a> {t<string>('transfer tx hash')}, <span>{t<string>(`The remaining claim limit is `)}<span style={{'color': '#ff8812', 'textDecoration': 'underline', 'fontStyle': 'italic'}}>{formatBalance(csmClaimLimit, {  decimals: 12, withUnit: 'CSM' })}</span><span>{t<string>(`, If your claim amount is greater than the claim limit, please wait for the limit update`)}</span></span>
            </h3>

           <InputAddress
              defaultValue={accountId}
              help={t<string>('The account you want to claim to.')}
              isDisabled={ethereumTxHashValid}
              label={t<string>('claim to account')}
              onChange={setAccountId}
              type='account'
            />
            <Input
              autoFocus
              className='full'
              help={t<string>('The Ethereum CSM transfer tx hash (starting by "0x")')}
              isDisabled={ethereumTxHashValid}
              isError={!isValid}
              label={t<string>('Ethereum tx hash')}
              onChange={onChangeEthereumTxHash}
              placeholder={t<string>('0x prefixed hex, e.g. 0x1234 or ascii data')}
              value={ethereumTxHash || ''}
            />
            {(step === Step.Account) && (<Button.Group>
              <Button
                icon='sign-in-alt'
                isBusy={isBusy}
                isDisabled={preclaimEthereumAddress === PRECLAIMS_LOADING || ethereumTxHash === null || ethereumTxHash === '' || !isValid}
                label={preclaimEthereumAddress === PRECLAIMS_LOADING
                  ? t<string>('Loading')
                  : t<string>('Continue')
                }
                onClick={handleAccountStep}
              />
            </Button.Group>)}
            
            <HttpStatus
              isStatusOpen={statusOpen}
              message={result}
              setStatusOpen={setStatusOpen}
              status={status}
            />
          </Card>)}
          {
            // We need to know the ethereuem address only for the new process
            // to be able to know the statement kind so that the users can sign it
            (step >= Step.ETHAddress && !isPreclaimed && !isOldClaimProcess) && (
              <Card withBottomMargin>
                <h3>{t<string>('2. Enter the ETH address from the sale.')}</h3>
                <Input
                  autoFocus
                  className='full'
                  help={t<string>('The the Ethereum address you used during the pre-sale (starting by "0x")')}
                  label={t<string>('Pre-sale ethereum address')}
                  onChange={onChangeEthereumAddress}
                  value={ethereumAddress || ''}
                />
                {(step === Step.ETHAddress) && (
                  <Button.Group>
                    <Button
                      icon='sign-in-alt'
                      isDisabled={!ethereumAddress}
                      label={t<string>('Continue')}
                      onClick={goToStepSign}
                    />
                  </Button.Group>
                )}
              </Card>
            )}
          {(step >= Step.Sign && !isPreclaimed) && (
            <Card>
              <h3>{t<string>('{{step}}. Sign with your ETH address', { replace: { step: isOldClaimProcess ? '2' : '3' } })}</h3>
              {!isOldClaimProcess && (
                <Statement
                  kind={statementKind}
                  systemChain={systemChain}
                />
              )}
              <div>{t<string>('Copy the following string and sign it with the Ethereum account you used during the pre-sale in the wallet of your choice, using the string as the payload, and then paste the transaction signature object below:')}</div>
              <CopyToClipboard
                onCopy={onCopy}
                text={payload}
              >
                <Payload
                  data-for='tx-payload'
                  data-tip
                >
                  {payload}
                </Payload>
              </CopyToClipboard>
              <Tooltip
                place='right'
                text={didCopy ? t<string>('copied') : t<string>('click to copy')}
                trigger='tx-payload'
              />
              <div>{t<string>('Paste the signed message into the field below. The placeholder text is there as a hint to what the message should look like:')}</div>
              <Signature
                onChange={onChangeSignature}
                placeholder={`{\n  "address": "0x ...",\n  "msg": "${prefix}...",\n  "sig": "0x ...",\n  "version": "3",\n  "signer": "..."\n}`}
                rows={10}
              />
              {(step === Step.Sign) && (
                <Button.Group>
                  <Button
                    icon='sign-in-alt'
                    isDisabled={!accountId || !signature}
                    label={t<string>('Confirm claim')}
                    onClick={goToStepClaim}
                  />
                </Button.Group>
              )}
            </Card>
          )}
        </Columar.Column>
        <Columar.Column>
          {(step >= Step.Claim) && (
            isPreclaimed
              ? <AttestDisplay
                accountId={accountId}
                ethereumAddress={ethereumAddress}
                onSuccess={goToStepAccount}
                statementKind={statementKind}
                systemChain={systemChain}
              />
              : <ClaimDisplay
                accountId={accountId}
                ethereumAddress={ethereumAddress}
                ethereumSignature={signature}
                isOldClaimProcess={isOldClaimProcess}
                onSuccess={goToStepAccount}
                statementKind={statementKind}
                ethereumTxHash={ethereumTxHash}
              />
          )}
        </Columar.Column>
      </Columar>
    </main>
  );
}
Example #29
Source File: test-precompile-local-assets-erc20.ts    From moonbeam with GNU General Public License v3.0 4 votes vote down vote up
describeDevMoonbeamAllEthTxTypes(
  "Precompiles - Assets-ERC20 Wasm",
  (context) => {
    let sudoAccount, baltatharAccount, assetId, iFace, assetAddress, contractInstanceAddress;
    before("Setup contract and mock balance", async () => {
      const keyring = new Keyring({ type: "ethereum" });
      sudoAccount = await keyring.addFromUri(ALITH_PRIV_KEY, null, "ethereum");
      baltatharAccount = await keyring.addFromUri(BALTATHAR_PRIV_KEY, null, "ethereum");

      // registerAsset
      const { events: eventsRegister } = await createBlockWithExtrinsic(
        context,
        sudoAccount,
        context.polkadotApi.tx.sudo.sudo(
          context.polkadotApi.tx.assetManager.registerLocalAsset(
            baltatharAccount.address,
            baltatharAccount.address,
            true,
            new BN(1)
          )
        )
      );

      // Look for assetId in events
      eventsRegister.forEach((e) => {
        if (e.section.toString() === "assetManager") {
          assetId = e.data[0].toHex();
        }
      });
      assetId = assetId.replace(/,/g, "");

      // Set metadata
      await createBlockWithExtrinsic(
        context,
        baltatharAccount,
        context.polkadotApi.tx.localAssets.setMetadata(assetId, "Local", "Local", new BN(12))
      );

      // mint asset
      await createBlockWithExtrinsic(
        context,
        baltatharAccount,
        context.polkadotApi.tx.localAssets.mint(assetId, baltatharAccount.address, 100000000000000)
      );

      assetAddress = u8aToHex(new Uint8Array([...hexToU8a("0xFFFFFFFE"), ...hexToU8a(assetId)]));

      const contractData = await getCompiled("LocalAssetExtendedErc20Instance");
      iFace = new ethers.utils.Interface(contractData.contract.abi);
      const { contract, rawTx } = await createContract(context, "LocalAssetExtendedErc20Instance");
      contractInstanceAddress = contract.options.address;
      await context.createBlock({ transactions: [rawTx] });
    });

    it("allows to call name", async function () {
      let data = iFace.encodeFunctionData(
        // action
        "name",
        []
      );

      const tx_call = await customWeb3Request(context.web3, "eth_call", [
        {
          from: ALITH,
          value: "0x0",
          gas: "0x10000",
          gasPrice: GAS_PRICE,
          to: assetAddress,
          data: data,
        },
      ]);

      let expected = stringToHex("Local");
      let offset = numberToHex(32).slice(2).padStart(64, "0");
      let length = numberToHex(5).slice(2).padStart(64, "0");
      // Bytes are padded at the end
      let expected_hex = expected.slice(2).padEnd(64, "0");
      expect(tx_call.result).equals("0x" + offset + length + expected_hex);
    });

    it("allows to call symbol", async function () {
      let data = iFace.encodeFunctionData(
        // action
        "symbol",
        []
      );

      const tx_call = await customWeb3Request(context.web3, "eth_call", [
        {
          from: GENESIS_ACCOUNT,
          value: "0x0",
          gas: "0x10000",
          gasPrice: GAS_PRICE,
          to: assetAddress,
          data: data,
        },
      ]);

      let expected = stringToHex("Local");
      let offset = numberToHex(32).slice(2).padStart(64, "0");
      let length = numberToHex(5).slice(2).padStart(64, "0");
      // Bytes are padded at the end
      let expected_hex = expected.slice(2).padEnd(64, "0");
      expect(tx_call.result).equals("0x" + offset + length + expected_hex);
    });

    it("allows to call decimals", async function () {
      let data = iFace.encodeFunctionData(
        // action
        "decimals",
        []
      );

      const tx_call = await customWeb3Request(context.web3, "eth_call", [
        {
          from: GENESIS_ACCOUNT,
          value: "0x0",
          gas: "0x10000",
          gasPrice: GAS_PRICE,
          to: assetAddress,
          data: data,
        },
      ]);

      let expected = "0x" + numberToHex(12).slice(2).padStart(64, "0");
      expect(tx_call.result).equals(expected);
    });

    it("allows to call getBalance", async function () {
      let data = iFace.encodeFunctionData(
        // action
        "balanceOf",
        [BALTATHAR]
      );

      const tx_call = await customWeb3Request(context.web3, "eth_call", [
        {
          from: GENESIS_ACCOUNT,
          value: "0x0",
          gas: "0x10000",
          gasPrice: GAS_PRICE,
          to: assetAddress,
          data: data,
        },
      ]);
      let amount = new BN(100000000000000);

      let amount_hex = "0x" + bnToHex(amount).slice(2).padStart(64, "0");
      expect(tx_call.result).equals(amount_hex);
    });

    it("allows to call totalSupply", async function () {
      let data = iFace.encodeFunctionData(
        // action
        "totalSupply",
        []
      );
      const tx_call = await customWeb3Request(context.web3, "eth_call", [
        {
          from: GENESIS_ACCOUNT,
          value: "0x0",
          gas: "0x10000",
          gasPrice: GAS_PRICE,
          to: assetAddress,
          data: data,
        },
      ]);

      let amount = new BN(100000000000000);

      let amount_hex = "0x" + bnToHex(amount).slice(2).padStart(64, "0");
      expect(tx_call.result).equals(amount_hex);
    });
  },
  true
);