@polkadot/keyring#decodeAddress TypeScript Examples

The following examples show how to use @polkadot/keyring#decodeAddress. 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: account.ts    From commonwealth with GNU General Public License v3.0 6 votes vote down vote up
public fromAddress(address: string, isEd25519 = false): SubstrateAccount {
    try {
      decodeAddress(address); // try to decode address; this will produce an error if the address is invalid
    } catch (e) {
      console.error(`Decoded invalid address: ${address}`);
      return;
    }
    try {
      const acct = this._store.getByAddress(address);
      // update account key type if created with incorrect settings
      if (acct.isEd25519 !== isEd25519) {
        return new SubstrateAccount(this.app, this._Chain, this, address, isEd25519);
      } else {
        return acct;
      }
    } catch (e) {
      return new SubstrateAccount(this.app, this._Chain, this, address, isEd25519);
    }
  }
Example #2
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 #3
Source File: transfer-to-parachain.ts    From interbtc-ui with Apache License 2.0 6 votes vote down vote up
createBeneficiary = (api: ApiPromise, id: string) => {
  const network = api.createType('XcmV0JunctionNetworkId', { any: true });
  const x1 = api.createType('XcmV1Junction', {
    accountId32: {
      network,
      id: decodeAddress(id)
    }
  });
  const interior = api.createType('XcmV1MultilocationJunctions', { x1 });
  const v1 = api.createType('XcmV1MultiLocation', { parents: 0, interior });

  return api.createType('XcmVersionedMultiLocation', {
    v1
  });
}
Example #4
Source File: validate.ts    From subscan-multisig-react with Apache License 2.0 6 votes vote down vote up
isSS58Address = (address: string) => {
  try {
    encodeAddress(isHex(address) ? hexToU8a(address) : decodeAddress(address));

    return true;
  } catch (error) {
    return false;
  }
}
Example #5
Source File: account.ts    From commonwealth with GNU General Public License v3.0 5 votes vote down vote up
public isZero(address: string) {
    const decoded = decodeAddress(address);
    return decoded.every((v) => v === 0);
  }
Example #6
Source File: transfer-to-relay-chain.ts    From interbtc-ui with Apache License 2.0 5 votes vote down vote up
createDest = (api: ApiPromise, id: string) => {
  const network = api.createType('XcmV0JunctionNetworkId', { any: true });
  const x1 = api.createType('XcmV1Junction', { accountId32: { network, id: decodeAddress(id) } });
  const interior = api.createType('XcmV1MultilocationJunctions', { x1 });
  const v1 = api.createType('XcmV1MultiLocation', { parents: 1, interior });

  return api.createType('XcmVersionedMultiLocation', { v1 });
}
Example #7
Source File: transfer.test.ts    From squid with GNU General Public License v3.0 5 votes vote down vote up
ALICE_ADDR = toHex(decodeAddress(ALICE))
Example #8
Source File: transfer.test.ts    From squid with GNU General Public License v3.0 5 votes vote down vote up
BOB_ADDR = toHex(decodeAddress(BOB))
Example #9
Source File: verifyAddress.ts    From commonwealth with GNU General Public License v3.0 4 votes vote down vote up
verifySignature = async (
  models: DB,
  chain: ChainInstance,
  addressModel: AddressInstance,
  user_id: number,
  signatureString: string
): Promise<boolean> => {
  if (!chain) {
    log.error('no chain provided to verifySignature');
    return false;
  }

  let isValid: boolean;
  if (chain.base === ChainBase.Substrate) {
    //
    // substrate address handling
    //
    const address = decodeAddress(addressModel.address);
    const keyringOptions: KeyringOptions = { type: 'sr25519' };
    if (
      !addressModel.keytype ||
      addressModel.keytype === 'sr25519' ||
      addressModel.keytype === 'ed25519'
    ) {
      if (addressModel.keytype) {
        keyringOptions.type = addressModel.keytype as KeypairType;
      }
      keyringOptions.ss58Format = chain.ss58_prefix ?? 42;
      const signerKeyring = new Keyring(keyringOptions).addFromAddress(address);
      const signedMessageNewline = stringToU8a(
        `${addressModel.verification_token}\n`
      );
      const signedMessageNoNewline = stringToU8a(
        addressModel.verification_token
      );
      const signatureU8a =
        signatureString.slice(0, 2) === '0x'
          ? hexToU8a(signatureString)
          : hexToU8a(`0x${signatureString}`);
      isValid =
        signerKeyring.verify(signedMessageNewline, signatureU8a, address) ||
        signerKeyring.verify(signedMessageNoNewline, signatureU8a, address);
    } else {
      log.error('Invalid keytype.');
      isValid = false;
    }
  } else if (
    chain.base === ChainBase.CosmosSDK &&
    addressModel.wallet_id === WalletId.CosmosEvmMetamask
  ) {
    //
    // ethereum address handling on cosmos chains
    //
    const msgBuffer = Buffer.from(addressModel.verification_token.trim());
    // toBuffer() doesn't work if there is a newline
    const msgHash = ethUtil.hashPersonalMessage(msgBuffer);
    const ethSignatureParams = ethUtil.fromRpcSig(signatureString.trim());
    const publicKey = ethUtil.ecrecover(
      msgHash,
      ethSignatureParams.v,
      ethSignatureParams.r,
      ethSignatureParams.s
    );

    const addressBuffer = ethUtil.publicToAddress(publicKey);
    const lowercaseAddress = ethUtil.bufferToHex(addressBuffer);
    try {
      // const ethAddress = Web3.utils.toChecksumAddress(lowercaseAddress);
      const injAddrBuf = ethUtil.Address.fromString(
        lowercaseAddress.toString()
      ).toBuffer();
      const injAddress = bech32.encode(
        chain.bech32_prefix,
        bech32.toWords(injAddrBuf)
      );
      if (addressModel.address === injAddress) isValid = true;
    } catch (e) {
      isValid = false;
    }
  } else if (chain.base === ChainBase.CosmosSDK && chain.bech32_prefix === 'terra') {
        //
    // cosmos-sdk address handling
    //

    // provided string should be serialized AminoSignResponse object
    const { signature: stdSignature } =
      JSON.parse(signatureString);

    // we generate an address from the actual public key and verify that it matches,
    // this prevents people from using a different key to sign the message than
    // the account they registered with.
    // TODO: ensure ion works
    const bech32Prefix = chain.bech32_prefix;
    if (!bech32Prefix) {
      log.error('No bech32 prefix found.');
      isValid = false;
    } else {
      const generatedAddress = pubkeyToAddress(
        stdSignature.pub_key,
        bech32Prefix
      );

      if (generatedAddress === addressModel.address) {
        try {
          // directly verify the generated signature, generated via SignBytes
          const { pubkey, signature } = decodeSignature(stdSignature)
          const secpSignature = Secp256k1Signature.fromFixedLength(signature);
          const messageHash = new Sha256(
            Buffer.from(addressModel.verification_token.trim())
          ).digest();

          isValid = await Secp256k1.verifySignature(
            secpSignature,
            messageHash,
            pubkey
          );
        } catch (e) {
          isValid = false;
        }
      }
    }
  } else if (chain.base === ChainBase.CosmosSDK) {
    //
    // cosmos-sdk address handling
    //

    // provided string should be serialized AminoSignResponse object
    const { signed, signature: stdSignature }: AminoSignResponse =
      JSON.parse(signatureString);

    // we generate an address from the actual public key and verify that it matches,
    // this prevents people from using a different key to sign the message than
    // the account they registered with.
    // TODO: ensure ion works
    const bech32Prefix = chain.bech32_prefix;
    if (!bech32Prefix) {
      log.error('No bech32 prefix found.');
      isValid = false;
    } else {
      const generatedAddress = pubkeyToAddress(
        stdSignature.pub_key,
        bech32Prefix
      );
      const generatedAddressWithCosmosPrefix = pubkeyToAddress(
        stdSignature.pub_key,
        'cosmos'
      );

      if (
        generatedAddress === addressModel.address ||
        generatedAddressWithCosmosPrefix === addressModel.address
      ) {

        let generatedSignDoc: StdSignDoc;

        try {
          // query chain ID from URL
          const node = await chain.getChainNode();
          const client = await StargateClient.connect(node.url);
          const chainId = await client.getChainId();
          client.disconnect();

          generatedSignDoc = validationTokenToSignDoc(
            chainId,
            addressModel.verification_token.trim(),
            signed.fee,
            signed.memo,
            <any>signed.msgs
          );
        } catch (e) {
          log.info(e.message);
        }

        // ensure correct document was signed
        if (
          generatedSignDoc &&
          serializeSignDoc(signed).toString() ===
          serializeSignDoc(generatedSignDoc).toString()
        ) {
          // ensure valid signature
          const { pubkey, signature } = decodeSignature(stdSignature);

          const secpSignature = Secp256k1Signature.fromFixedLength(signature);
          const messageHash = new Sha256(
            serializeSignDoc(generatedSignDoc)
          ).digest();


          isValid = await Secp256k1.verifySignature(
            secpSignature,
            messageHash,
            pubkey
          );

          if (!isValid) {
            log.error('Signature verification failed.');
          }
        } else {
          log.error(
            `Sign doc not matched. Generated: ${JSON.stringify(
              generatedSignDoc
            )}, found: ${JSON.stringify(signed)}.`
          );
          isValid = false;
        }
      } else {
        log.error(
          `Address not matched. Generated ${generatedAddress}, found ${addressModel.address}.`
        );
        isValid = false;
      }
    }
  } else if (chain.base === ChainBase.Ethereum) {
    //
    // ethereum address handling
    //
    try {
      const node = await chain.getChainNode();
      const typedMessage = constructTypedMessage(node.eth_chain_id || 1, addressModel.verification_token.trim());
      const address = recoverTypedSignature({
        data: typedMessage,
        signature: signatureString.trim(),
        version: SignTypedDataVersion.V4,
      });
      isValid = addressModel.address.toLowerCase() === address.toLowerCase();
      if (!isValid) {
        log.info(
          `Eth verification failed for ${addressModel.address}: does not match recovered address ${address}`
        );
      }
    } catch (e) {
      log.info(
        `Eth verification failed for ${addressModel.address}: ${e.message}`
      );
      isValid = false;
    }
  } else if (chain.base === ChainBase.NEAR) {
    //
    // near address handling
    //

    // both in base64 encoding
    const { signature: sigObj, publicKey } = JSON.parse(signatureString);
    isValid = nacl.sign.detached.verify(
      Buffer.from(`${addressModel.verification_token}\n`),
      Buffer.from(sigObj, 'base64'),
      Buffer.from(publicKey, 'base64')
    );
  } else if (chain.base === ChainBase.Solana) {
    //
    // solana address handling
    //

    // ensure address is base58 string length 32, cf @solana/web3 impl
    try {
      const decodedAddress = bs58.decode(addressModel.address);
      if (decodedAddress.length === 32) {
        isValid = nacl.sign.detached.verify(
          Buffer.from(`${addressModel.verification_token}`),
          Buffer.from(signatureString, 'base64'),
          decodedAddress
        );
      } else {
        isValid = false;
      }
    } catch (e) {
      isValid = false;
    }
  } else {
    // invalid network
    log.error(`invalid network: ${chain.network}`);
    isValid = false;
  }

  addressModel.last_active = new Date();

  if (isValid && user_id === null) {
    // mark the address as verified, and if it doesn't have an associated user, create a new user
    addressModel.verification_token_expires = null;
    addressModel.verified = new Date();
    if (!addressModel.user_id) {
      const user = await models.User.createWithProfile(models, { email: null });
      addressModel.profile_id = (user.Profiles[0] as ProfileAttributes).id;
      await models.Subscription.create({
        subscriber_id: user.id,
        category_id: NotificationCategories.NewMention,
        object_id: `user-${user.id}`,
        is_active: true,
      });
      await models.Subscription.create({
        subscriber_id: user.id,
        category_id: NotificationCategories.NewCollaboration,
        object_id: `user-${user.id}`,
        is_active: true,
      });
      addressModel.user_id = user.id;
    }
  } else if (isValid) {
    // mark the address as verified
    addressModel.verification_token_expires = null;
    addressModel.verified = new Date();
    addressModel.user_id = user_id;
    const profile = await models.Profile.findOne({ where: { user_id } });
    addressModel.profile_id = profile.id;
  }
  await addressModel.save();
  return isValid;
}