web3-utils#isAddress TypeScript Examples

The following examples show how to use web3-utils#isAddress. 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: helpers.ts    From webapp with MIT License 6 votes vote down vote up
removeLeadingZeros = (hexString: string) => {
  const removedOx = hexString.startsWith("0x") ? hexString.slice(2) : hexString;

  const noLeadingZeros =
    "0x" + removedOx.slice(removedOx.split("").findIndex(x => x !== "0"));

  const attempts = [...Array(60)].map((_, index) => index);

  const correctAttemptNumber = attempts.find(attemptNumber => {
    const result = addZeros(attemptNumber, noLeadingZeros);
    return isAddress(result);
  });

  if (typeof correctAttemptNumber !== "undefined") {
    return addZeros(correctAttemptNumber, noLeadingZeros);
  } else throw new Error(`Failed parsing hex ${hexString}`);
}
Example #2
Source File: ethWallet.ts    From webapp with MIT License 6 votes vote down vote up
@action async transfer({
    floatAmount,
    recipient
  }: {
    floatAmount: string;
    recipient: string;
  }) {
    if (!floatAmount) throw new Error("Float Amount required.");
    if (!isAddress(recipient))
      throw new Error("Recipient must be valid ETH address");
    const weiAmount = toWei(floatAmount);
    const value = toHex(weiAmount);
    const params = [
      {
        from: this.currentUser,
        to: recipient,
        value
      }
    ];
    return this.tx(params);
  }
Example #3
Source File: eth-like-web3-public.ts    From rubic-app with GNU General Public License v3.0 5 votes vote down vote up
/**
   * Checks if a given address is a valid Ethereum address.
   * @param address The address to check validity.
   */
  public isAddressCorrect(address: string): boolean {
    return isAddress(address);
  }
Example #4
Source File: web3-pure.ts    From rubic-sdk with GNU General Public License v3.0 5 votes vote down vote up
/**
     * @description checks if a given address is a valid Ethereum address
     * @param address the address to check validity
     */
    static isAddressCorrect(address: string): boolean {
        return isAddress(address);
    }
Example #5
Source File: currencyFunctions.ts    From core with MIT License 5 votes vote down vote up
isETHAddress = (address: string) => {
  return isAddress(address);
}
Example #6
Source File: erc20_form.tsx    From commonwealth with GNU General Public License v3.0 4 votes vote down vote up
view(vnode) {
    const validAddress = isAddress(this.state.form.address);
    const disableField = !validAddress || !this.state.loaded;

    const updateTokenForum = async () => {
      if (!this.state.form.address || !this.state.form.ethChainId) return;
      this.state.status = '';
      this.state.error = '';
      this.state.loading = true;
      const args = {
        address: this.state.form.address,
        chain_id: this.state.form.ethChainId,
        chain_network: ChainNetwork.ERC20,
        url: this.state.form.nodeUrl,
        allowUncached: true,
      };
      try {
        console.log('Querying backend for token data');
        const res = await $.get(`${app.serverUrl()}/getTokenForum`, args);
        if (res.status === 'Success') {
          if (res?.token?.name) {
            this.state.form.name = res.token.name || '';
            this.state.form.id = res.token.id && slugify(res.token.id);
            this.state.form.symbol = res.token.symbol || '';
            this.state.form.decimals = +res.token.decimals || 18;
            this.state.form.iconUrl = res.token.icon_url || '';
            if (this.state.form.iconUrl.startsWith('/')) {
              this.state.form.iconUrl = `https://commonwealth.im${this.state.form.iconUrl}`;
            }
            this.state.form.description = res.token.description || '';
            this.state.form.website = res.token.website || '';
            this.state.form.discord = res.token.discord || '';
            this.state.form.element = res.token.element || '';
            this.state.form.telegram = res.token.telegram || '';
            this.state.form.github = res.token.github || '';
            this.state.status = 'Success!';
          } else {
            // attempt to query ERC20Detailed token info from chain
            console.log('Querying chain for ERC info');
            const provider = new Web3.providers.WebsocketProvider(args.url);
            try {
              const ethersProvider = new providers.Web3Provider(provider);
              const contract = IERC20Metadata__factory.connect(
                args.address,
                ethersProvider
              );
              const name = await contract.name();
              const symbol = await contract.symbol();
              const decimals = await contract.decimals();
              this.state.form.name = name || '';
              this.state.form.id = name && slugify(name);
              this.state.form.symbol = symbol || '';
              this.state.form.decimals = decimals || 18;
              this.state.status = 'Success!';
            } catch (e) {
              this.state.form.name = '';
              this.state.form.id = '';
              this.state.form.symbol = '';
              this.state.form.decimals = 18;
              this.state.status = 'Verified token but could not load metadata.';
            }
            this.state.form.iconUrl = '';
            this.state.form.description = '';
            this.state.form.website = '';
            this.state.form.discord = '';
            this.state.form.element = '';
            this.state.form.telegram = '';
            this.state.form.github = '';
            provider.disconnect(1000, 'finished');
          }
          this.state.loaded = true;
        } else {
          this.state.error = res.message || 'Failed to load Token Information';
        }
      } catch (err) {
        this.state.error =
          err.responseJSON?.error || 'Failed to load Token Information';
      }
      this.state.loading = false;
      m.redraw();
    };

    return (
      <div class="CreateCommunityForm">
        {...ethChainRows(vnode.attrs, this.state.form)}
        <CWButton
          label="Populate fields"
          disabled={
            this.state.saving ||
            !validAddress ||
            !this.state.form.ethChainId ||
            this.state.loading
          }
          onclick={async () => {
            await updateTokenForum();
          }}
        />
        <ValidationRow error={this.state.error} status={this.state.status} />
        <InputRow
          title="Name"
          defaultValue={this.state.form.name}
          disabled={disableField}
          onChangeHandler={(v) => {
            this.state.form.name = v;
            this.state.form.id = slugifyPreserveDashes(v);
          }}
        />
        <IdRow id={this.state.form.id} />
        <InputRow
          title="Symbol"
          disabled={disableField}
          defaultValue={this.state.form.symbol}
          placeholder="XYZ"
          onChangeHandler={(v) => {
            this.state.form.symbol = v;
          }}
        />
        {...defaultChainRows(this.state.form, disableField)}
        <CWButton
          label="Save changes"
          disabled={this.state.saving || !validAddress || !this.state.loaded}
          onclick={async () => {
            const { altWalletUrl, chainString, ethChainId, nodeUrl } =
              this.state.form;
            this.state.saving = true;
            mixpanelBrowserTrack({
              event: MixpanelCommunityCreationEvent.CREATE_COMMUNITY_ATTEMPTED,
              chainBase: null,
              isCustomDomain: app.isCustomDomain(),
              communityType: null,
            });
            try {
              const res = await $.post(`${app.serverUrl()}/createChain`, {
                alt_wallet_url: altWalletUrl,
                base: ChainBase.Ethereum,
                chain_string: chainString,
                eth_chain_id: ethChainId,
                jwt: app.user.jwt,
                network: ChainNetwork.ERC20,
                node_url: nodeUrl,
                type: ChainType.Token,
                ...this.state.form,
              });
              await initAppState(false);
              m.route.set(`/${res.result.chain?.id}`);
            } catch (err) {
              notifyError(
                err.responseJSON?.error || 'Creating new ERC20 community failed'
              );
            } finally {
              this.state.saving = false;
            }
          }}
        />
      </div>
    );
  }
Example #7
Source File: erc721_form.tsx    From commonwealth with GNU General Public License v3.0 4 votes vote down vote up
view(vnode) {
    const validAddress = isAddress(this.state.form.address);
    const disableField = !validAddress || !this.state.loaded;

    const updateTokenForum = async () => {
      if (!this.state.form.address || !this.state.form.ethChainId) return;
      this.state.status = '';
      this.state.error = '';
      this.state.loading = true;
      const args = {
        address: this.state.form.address,
        chain_id: this.state.form.ethChainId,
        chain_network: ChainNetwork.ERC721,
        url: this.state.form.nodeUrl,
        allowUncached: true,
      };
      try {
        console.log('Querying backend for token data');
        const res = await $.get(`${app.serverUrl()}/getTokenForum`, args);
        if (res.status === 'Success') {
          if (res?.token?.name) {
            this.state.form.name = res.token.name || '';
            this.state.form.id = res.token.id && slugify(res.token.id);
            this.state.form.symbol = res.token.symbol || '';
            this.state.form.iconUrl = res.token.icon_url || '';
            if (this.state.form.iconUrl.startsWith('/')) {
              this.state.form.iconUrl = `https://commonwealth.im${this.state.form.iconUrl}`;
            }
            this.state.form.description = res.token.description || '';
            this.state.form.website = res.token.website || '';
            this.state.form.discord = res.token.discord || '';
            this.state.form.element = res.token.element || '';
            this.state.form.telegram = res.token.telegram || '';
            this.state.form.github = res.token.github || '';
            this.state.status = 'Success!';
          } else {
            // attempt to query ERC721Detailed token info from chain
            console.log('Querying chain for ERC info');
            const provider = new Web3.providers.WebsocketProvider(args.url);
            try {
              const ethersProvider = new providers.Web3Provider(provider);
              const contract = IERC721Metadata__factory.connect(
                args.address,
                ethersProvider
              );
              const name = await contract.name();
              const symbol = await contract.symbol();
              const decimals = await contract.decimals();
              this.state.form.name = name || '';
              this.state.form.id = name && slugify(name);
              this.state.form.symbol = symbol || '';
              this.state.status = 'Success!';
            } catch (e) {
              this.state.form.name = '';
              this.state.form.id = '';
              this.state.form.symbol = '';
              this.state.status = 'Verified token but could not load metadata.';
            }
            this.state.form.iconUrl = '';
            this.state.form.description = '';
            this.state.form.website = '';
            this.state.form.discord = '';
            this.state.form.element = '';
            this.state.form.telegram = '';
            this.state.form.github = '';
            provider.disconnect(1000, 'finished');
          }
          this.state.loaded = true;
        } else {
          this.state.error = res.message || 'Failed to load Token Information';
        }
      } catch (err) {
        this.state.error =
          err.responseJSON?.error || 'Failed to load Token Information';
      }
      this.state.loading = false;
      m.redraw();
    };

    return (
      <div class="CreateCommunityForm">
        {...ethChainRows(vnode.attrs, this.state.form)}
        <CWButton
          label="Populate fields"
          disabled={
            this.state.saving ||
            !validAddress ||
            !this.state.form.ethChainId ||
            this.state.loading
          }
          onclick={async () => {
            await updateTokenForum();
          }}
        />
        <ValidationRow error={this.state.error} status={this.state.status} />
        <InputRow
          title="Name"
          defaultValue={this.state.form.name}
          disabled={disableField}
          onChangeHandler={(v) => {
            this.state.form.name = v;
            this.state.form.id = slugifyPreserveDashes(v);
          }}
        />
        <IdRow id={this.state.form.id} />
        <InputRow
          title="Symbol"
          disabled={disableField}
          defaultValue={this.state.form.symbol}
          placeholder="XYZ"
          onChangeHandler={(v) => {
            this.state.form.symbol = v;
          }}
        />
        {...defaultChainRows(this.state.form, disableField)}
        <CWButton
          label="Save changes"
          disabled={this.state.saving || !validAddress || !this.state.loaded}
          onclick={async () => {
            const { altWalletUrl, chainString, ethChainId, nodeUrl } =
              this.state.form;
            this.state.saving = true;
            mixpanelBrowserTrack({
              event: MixpanelCommunityCreationEvent.CREATE_COMMUNITY_ATTEMPTED,
              chainBase: null,
              isCustomDomain: app.isCustomDomain(),
              communityType: null,
            });

            try {
              const res = await $.post(`${app.serverUrl()}/createChain`, {
                alt_wallet_url: altWalletUrl,
                base: ChainBase.Ethereum,
                chain_string: chainString,
                eth_chain_id: ethChainId,
                jwt: app.user.jwt,
                network: ChainNetwork.ERC721,
                node_url: nodeUrl,
                type: ChainType.Token,
                ...this.state.form,
              });
              await initAppState(false);
              m.route.set(`/${res.result.chain?.id}`);
            } catch (err) {
              notifyError(
                err.responseJSON?.error ||
                  'Creating new ERC721 community failed'
              );
            } finally {
              this.state.saving = false;
            }
          }}
        />
      </div>
    );
  }
Example #8
Source File: eth_dao_form.tsx    From commonwealth with GNU General Public License v3.0 4 votes vote down vote up
view(vnode) {
    const validAddress = isAddress(this.state.form.address);
    const disableField = !validAddress || !this.state.loaded;

    const updateDAO = async () => {
      if (
        !this.state.form.address ||
        !this.state.form.ethChainId ||
        !this.state.form.nodeUrl
      )
        return;
      this.state.loading = true;
      this.state.status = '';
      this.state.error = '';
      try {
        if (this.state.form.network === ChainNetwork.Compound) {
          const provider = new Web3.providers.WebsocketProvider(
            this.state.form.nodeUrl
          );
          const compoundApi = new CompoundAPI(
            null,
            this.state.form.address,
            provider
          );
          await compoundApi.init(this.state.form.tokenName);
          if (!compoundApi.Token) {
            throw new Error(
              'Could not find governance token. Is "Token Name" field valid?'
            );
          }
          const govType = GovernorType[compoundApi.govType];
          const tokenType = GovernorTokenType[compoundApi.tokenType];
          this.state.status = `Found ${govType} with token type ${tokenType}`;
        } else if (this.state.form.network === ChainNetwork.Aave) {
          const provider = new Web3.providers.WebsocketProvider(
            this.state.form.nodeUrl
          );
          const aaveApi = new AaveApi(
            IAaveGovernanceV2__factory.connect,
            this.state.form.address,
            provider
          );
          await aaveApi.init();
          this.state.status = `Found Aave type DAO`;
        } else {
          throw new Error('invalid chain network');
        }
      } catch (e) {
        this.state.error = e.message;
        this.state.loading = false;
        m.redraw();
        return;
      }
      this.state.loaded = true;
      this.state.loading = false;
      m.redraw();
    };

    return (
      <div class="CreateCommunityForm">
        {...ethChainRows(vnode.attrs, this.state.form)}
        <SelectRow
          title="DAO Type"
          options={[ChainNetwork.Aave, ChainNetwork.Compound]}
          value={this.state.form.network}
          onchange={(value) => {
            this.state.form.network = value;
            this.state.loaded = false;
          }}
        />
        {this.state.form.network === ChainNetwork.Compound && (
          <InputRow
            title="Token Name (Case Sensitive)"
            defaultValue={this.state.form.tokenName}
            onChangeHandler={(v) => {
              this.state.form.tokenName = v;
              this.state.loaded = false;
            }}
          />
        )}
        <CWButton
          label="Test contract"
          disabled={
            this.state.saving ||
            !validAddress ||
            !this.state.form.ethChainId ||
            this.state.loading
          }
          onclick={async () => {
            await updateDAO();
          }}
        />
        <ValidationRow error={this.state.error} status={this.state.status} />
        <InputRow
          title="Name"
          defaultValue={this.state.form.name}
          disabled={disableField}
          onChangeHandler={(v) => {
            this.state.form.name = v;
            this.state.form.id = slugifyPreserveDashes(v);
          }}
        />
        <IdRow id={this.state.form.id} />
        <InputRow
          title="Symbol"
          disabled={disableField}
          defaultValue={this.state.form.symbol}
          placeholder="XYZ"
          onChangeHandler={(v) => {
            this.state.form.symbol = v;
          }}
        />
        {...defaultChainRows(this.state.form, disableField)}
        <CWButton
          label="Save changes"
          disabled={this.state.saving || !validAddress || !this.state.loaded}
          onclick={async () => {
            const { chainString, ethChainId, nodeUrl, tokenName } =
              this.state.form;
            this.state.saving = true;
            mixpanelBrowserTrack({
              event: MixpanelCommunityCreationEvent.CREATE_COMMUNITY_ATTEMPTED,
              chainBase: null,
              isCustomDomain: app.isCustomDomain(),
              communityType: null,
            });
            try {
              const res = await $.post(`${app.serverUrl()}/createChain`, {
                base: ChainBase.Ethereum,
                chain_string: chainString,
                eth_chain_id: ethChainId,
                jwt: app.user.jwt,
                node_url: nodeUrl,
                token_name: tokenName,
                type: ChainType.DAO,
                ...this.state.form,
              });
              await initAppState(false);
              // TODO: notify about needing to run event migration
              m.route.set(`/${res.result.chain?.id}`);
            } catch (err) {
              notifyError(
                err.responseJSON?.error ||
                  'Creating new ETH DAO community failed'
              );
            } finally {
              this.state.saving = false;
            }
          }}
        />
      </div>
    );
  }
Example #9
Source File: finishSsoLogin.ts    From commonwealth with GNU General Public License v3.0 4 votes vote down vote up
finishSsoLogin = async (
  models: DB,
  req: TypedRequestBody<FinishSsoLoginReq>,
  res: TypedResponse<FinishSsoLoginRes>
) => {
  // verify issuer (TODO: support other SSO endpoints)
  if (req.body.issuer !== Issuers.AxieInfinity) {
    throw new AppError(Errors.InvalidIssuer);
  } else if (!AXIE_SHARED_SECRET) {
    throw new ServerError(Errors.NoSharedSecret);
  }

  // verify request stateId (i.e. that /auth/sso was called)
  const emptyTokenInstance = await models.SsoToken.findOne({
    where: { state_id: req.body.stateId },
  });
  if (!emptyTokenInstance) {
    throw new AppError(Errors.InvalidTokenState);
  }

  // decode token payload
  const tokenString = req.body.token;
  if (!tokenString) {
    throw new AppError(Errors.MissingToken);
  }

  let jwtPayload: AxieInfinityJwt;
  try {
    const decoded = jwt.verify(tokenString, AXIE_SHARED_SECRET, {
      issuer: 'AxieInfinity',
    });
    if (isAxieInfinityJwt(decoded)) {
      jwtPayload = decoded;
    } else {
      throw new Error('Could not decode token');
    }
  } catch (e) {
    log.info(`Axie token decoding error: ${e.message}`);
    throw new AppError(Errors.InvalidToken);
  }

  // verify issuer
  if (jwtPayload.iss !== Issuers.AxieInfinity) {
    throw new AppError(Errors.TokenBadIssuer);
  }

  // verify expiration
  if (jwtPayload.iat + EXPIRATION_TIME < Math.floor(Date.now() / 1000)) {
    throw new AppError(Errors.TokenExpired);
  }

  // verify address
  if (!isAddress(jwtPayload.roninAddress)) {
    throw new AppError(Errors.TokenBadAddress);
  }

  // check if this is a new signup or a login
  const reqUser = req.user;
  const existingAddress = await models.Address.scope('withPrivateData').findOne(
    {
      where: { address: jwtPayload.roninAddress },
      include: [
        {
          model: models.SsoToken,
          where: { issuer: jwtPayload.iss },
          required: true,
        },
      ],
    }
  );
  if (existingAddress) {
    // TODO: transactionalize
    // if the address was removed by /deleteAddress, we need to re-verify it
    if (!existingAddress.verified) {
      existingAddress.verified = new Date();
      await existingAddress.save();
    }

    if (reqUser?.id && reqUser.id === existingAddress.user_id) {
      const newUser = await models.User.findOne({
        where: {
          id: reqUser.id,
        },
        include: [models.Address],
      });
      return success(res, { user: newUser });
    }

    // check login token, if the user has already logged in before with SSO
    const token = await existingAddress.getSsoToken();

    // perform login on existing account
    if (jwtPayload.iat <= token.issued_at) {
      log.error('Replay attack detected.');
      throw new AppError(Errors.ReplayAttack);
    }
    token.issued_at = jwtPayload.iat;
    token.state_id = emptyTokenInstance.state_id;
    await token.save();

    // delete the empty token that was initialized on /auth/sso, because it is superceded
    // by the existing token for this user
    await emptyTokenInstance.destroy();

    if (reqUser) {
      // perform address transfer
      // TODO: factor this email code into a util
      try {
        const oldUser = await models.User.scope('withPrivateData').findOne({
          where: { id: existingAddress.user_id },
        });
        if (!oldUser) {
          throw new Error('User should exist');
        }
        const msg = {
          to: oldUser.email,
          from: 'Commonwealth <[email protected]>',
          templateId: DynamicTemplate.VerifyAddress,
          dynamic_template_data: {
            address: existingAddress,
            chain: AXIE_INFINITY_CHAIN_ID,
          },
        };
        await sgMail.send(msg);
        log.info(
          `Sent address move email: ${existingAddress} transferred to a new account`
        );
      } catch (e) {
        log.error(`Could not send address move email for: ${existingAddress}`);
      }

      const newProfile = await models.Profile.findOne({
        where: { user_id: reqUser.id },
      });
      existingAddress.user_id = reqUser.id;
      existingAddress.profile_id = newProfile.id;
      await existingAddress.save();

      const newAddress = await models.Address.findOne({
        where: { id: existingAddress.id },
      });
      return success(res, { address: newAddress });
    } else {
      // user is not logged in, so we log them in
      const user = await models.User.findOne({
        where: {
          id: existingAddress.user_id,
        },
        include: [models.Address],
      });
      // TODO: should we req.login here, or not?
      req.login(user, (err) => {
        if (err)
          return redirectWithLoginError(
            res,
            `Could not log in with ronin wallet`
          );
        if (process.env.NODE_ENV !== 'test') {
          mixpanelTrack({
            event: MixpanelLoginEvent.LOGIN,
            isCustomDomain: null,
          });
        }
      });
      return success(res, { user });
    }
  }

  // create new address and user if needed + populate sso token
  try {
    const result = await sequelize.transaction(async (t) => {
      let user: Express.User;
      // TODO: this profile fetching will eventually need to assume more than one profile
      let profile: ProfileAttributes;
      if (!reqUser) {
        // create new user
        user = await models.User.createWithProfile(
          models,
          { email: null },
          { transaction: t }
        );
        profile = user.Profiles[0];
      } else {
        user = reqUser;
        profile = await models.Profile.findOne({ where: { user_id: user.id } });
      }

      // create new address
      const newAddress = await models.Address.create(
        {
          address: jwtPayload.roninAddress,
          chain: AXIE_INFINITY_CHAIN_ID,
          verification_token: 'SSO',
          verification_token_expires: null,
          verified: new Date(), // trust addresses from magic
          last_active: new Date(),
          user_id: user.id,
          profile_id: profile.id,
          wallet_id: WalletId.Ronin,
        },
        { transaction: t }
      );

      await models.Role.create(
        {
          address_id: newAddress.id,
          chain_id: AXIE_INFINITY_CHAIN_ID,
          permission: 'member',
        },
        { transaction: t }
      );

      // Automatically create subscription to their own mentions
      await models.Subscription.create(
        {
          subscriber_id: user.id,
          category_id: NotificationCategories.NewMention,
          object_id: `user-${user.id}`,
          is_active: true,
        },
        { transaction: t }
      );

      // Automatically create a subscription to collaborations
      await models.Subscription.create(
        {
          subscriber_id: user.id,
          category_id: NotificationCategories.NewCollaboration,
          object_id: `user-${user.id}`,
          is_active: true,
        },
        { transaction: t }
      );

      // populate token
      emptyTokenInstance.issuer = jwtPayload.iss;
      emptyTokenInstance.issued_at = jwtPayload.iat;
      emptyTokenInstance.address_id = newAddress.id;
      await emptyTokenInstance.save({ transaction: t });

      return user;
    });

    if (reqUser) {
      // re-fetch address if existing user
      const newAddress = await models.Address.findOne({
        where: { address: jwtPayload.roninAddress },
      });
      return success(res, { address: newAddress });
    } else {
      // re-fetch user to include address object, if freshly created
      const newUser = await models.User.findOne({
        where: {
          id: result.id,
        },
        include: [models.Address],
      });
      // TODO: should we req.login here? or not?
      req.login(newUser, (err) => {
        if (err)
          return redirectWithLoginError(
            res,
            `Could not log in with ronin wallet`
          );
        if (process.env.NODE_ENV !== 'test') {
          mixpanelTrack({
            event: MixpanelLoginEvent.LOGIN,
            isCustomDomain: null,
          });
        }
      });
      return success(res, { user: newUser });
    }
  } catch (e) {
    log.error(e.message);
    throw new ServerError(Errors.AccountCreationFailed);
  }
}