types#OrFalsy TypeScript Examples

The following examples show how to use types#OrFalsy. 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: blockTime.ts    From contracts-ui with GNU General Public License v3.0 6 votes vote down vote up
export function blockTimeMs(a: OrFalsy<ApiPromise>): BN {
  return (a?.consts.babe?.expectedBlockTime || // Babe
    // POW, eg. Kulupu
    a?.consts.difficulty?.targetBlockTime ||
    // Check against threshold to determine value validity
    (a?.consts.timestamp?.minimumPeriod.gte(THRESHOLD)
      ? // Default minimum period config
        a.consts.timestamp.minimumPeriod.mul(BN_TWO)
      : a?.query.parachainSystem
      ? // default guess for a parachain
        DEFAULT_TIME.mul(BN_TWO)
      : // default guess for others
        DEFAULT_TIME)) as BN;
}
Example #2
Source File: useMetadataField.tsx    From contracts-ui with GNU General Public License v3.0 6 votes vote down vote up
useMetadataField = (): UseMetadataField => {
  const navigate = useNavigate();
  const { codeHash: codeHashUrlParam } = useParams<{ codeHash: string }>();

  const [file, setFile] = useState<OrFalsy<FileState>>(null);

  const codeBundleQuery = useCodeBundle(codeHashUrlParam || '');
  const codeBundle = codeBundleQuery.data;
  const metadata = useMetadata(codeBundle?.document?.abi, {
    isWasmRequired: !codeBundle,
    onChange: setFile,
  });

  const isLoading = useMemo(
    () => !!codeHashUrlParam && codeBundleQuery.isLoading,
    [codeHashUrlParam, codeBundleQuery.isLoading]
  );

  const isStored = useMemo((): boolean => !!codeBundle?.document, [codeBundle?.document]);

  useEffect((): void => {
    if (codeHashUrlParam && !codeBundleQuery.isValid) {
      navigate(`/instantiate/${codeHashUrlParam}`);
    }
  }, [codeHashUrlParam, codeBundleQuery.isValid, navigate]);

  return {
    file,
    isLoading,
    isStored,
    ...metadata,
  };
}
Example #3
Source File: useAccountId.ts    From contracts-ui with GNU General Public License v3.0 6 votes vote down vote up
export function useAccountId(initialValue = '', isOwned = false): ValidFormField<string> {
  const { keyring } = useApi();

  const validate = useCallback(
    (value: OrFalsy<string>): Validation => {
      if (!value?.trim() || (isOwned && !keyring?.getAccount(value))) {
        return { isValid: false, message: 'Specified account does not exist' };
      }

      return { isValid: true, message: null };
    },
    [keyring, isOwned]
  );

  return useFormField<string>(initialValue || keyring?.getAccounts()[0].address || '', validate);
}
Example #4
Source File: useStorageDepositLimit.ts    From contracts-ui with GNU General Public License v3.0 6 votes vote down vote up
export function useStorageDepositLimit(accountId: OrFalsy<string>): UseStorageDepositLimit {
  const { api } = useApi();
  const [maximum, setMaximum] = useState<BN | null>(null);

  const storageDepositLimit = useBalance(0, { maxValue: maximum || undefined });

  useEffect((): void => {
    accountId &&
      api.derive.balances
        .account(accountId)
        .then(({ freeBalance }) => setMaximum(freeBalance))
        .catch(console.error);
  }, [accountId, api]);

  return {
    ...storageDepositLimit,
    maximum,
  };
}
Example #5
Source File: index.ts    From contracts-ui with GNU General Public License v3.0 5 votes vote down vote up
export function maximumBlockWeight(api: OrFalsy<ApiPromise>): Weight {
  return api?.consts.system.blockWeights
    ? api.consts.system.blockWeights.maxBlock
    : (api?.consts.system.maximumBlockWeight as Weight) || MAX_CALL_WEIGHT;
}
Example #6
Source File: Enum.tsx    From contracts-ui with GNU General Public License v3.0 5 votes vote down vote up
export function Enum(props: Props) {
  const { components, typeDef, onChange: _onChange, registry, value = {} } = props;
  const variants = typeDef.sub as TypeDef[];
  const { keyring } = useApi();
  const [variantIndex, _setVariantIndex] = useState<number>(
    Math.max(
      0,
      variants.findIndex(({ name }) => name === Object.keys(value)[0])
    )
  );

  const Component = components[variantIndex];

  const onChange = useCallback(
    (value: unknown): void => {
      _onChange({ [variants[variantIndex].name as string]: value });
    },
    [_onChange, variants, variantIndex]
  );

  const setVariantIndex = useCallback(
    (value: OrFalsy<number>) => {
      if (isNumber(value)) {
        _setVariantIndex(value);

        _onChange({
          [variants[value].name as string]: getInitValue(registry, keyring, variants[value]),
        });
      }
    },
    [registry, keyring, _onChange, variants]
  );

  return (
    <>
      <Dropdown
        options={variants.map(({ name }, index) => ({ label: name, value: index }))}
        value={variantIndex}
        onChange={setVariantIndex}
      />
      {variants[variantIndex].type !== 'Null' && (
        <FormField
          className="ml-8 mt-2"
          label={<ArgSignature arg={{ type: variants[variantIndex] }} />}
          {...getValidation(props)}
        >
          <Component value={Object.values(value)[0]} onChange={onChange} />
        </FormField>
      )}
    </>
  );
}
Example #7
Source File: InputBalance.tsx    From contracts-ui with GNU General Public License v3.0 5 votes vote down vote up
function getStringValue(api: ApiPromise, value: OrFalsy<BN>) {
  if (!value) {
    return '';
  }

  return fromBalance(fromSats(api, value || BN_ZERO));
}
Example #8
Source File: Option.tsx    From contracts-ui with GNU General Public License v3.0 5 votes vote down vote up
export function Option({
  component: Component,
  onChange: _onChange,
  registry,
  typeDef,
  value = null,
}: Props) {
  const { keyring } = useApi();

  const [isSupplied, toggleIsSupplied] = useToggle();
  const onChange = useCallback(
    (value: OrFalsy<unknown>): void => {
      if (!isSupplied) {
        _onChange(null);

        return;
      }

      _onChange(value);
    },
    [_onChange, isSupplied]
  );

  useEffect((): void => {
    if (isSupplied && value === null) {
      onChange(getInitValue(registry, keyring, typeDef.sub as TypeDef));
    } else {
      if (!isSupplied && value !== null) {
        onChange(null);
      }
    }
  }, [keyring, registry, onChange, value, isSupplied, typeDef.sub]);

  return (
    <div className="flex items-start">
      {isSupplied ? (
        <Component className="flex-1" onChange={onChange} value={value} />
      ) : (
        <Input className="flex-1" isDisabled onChange={NOOP} value="" placeholder="Do not supply" />
      )}
      <div className="flex justify-center items-center w-18 my-2.5">
        <Switch value={isSupplied} onChange={toggleIsSupplied} />
      </div>
    </div>
  );
}
Example #9
Source File: useCodeBundle.ts    From contracts-ui with GNU General Public License v3.0 5 votes vote down vote up
function isValidHash(input: OrFalsy<string>): boolean {
  const codeHashRegex = /^0x[0-9a-fA-F]{64}$/;
  return !!input && codeHashRegex.test(input);
}
Example #10
Source File: useWeight.ts    From contracts-ui with GNU General Public License v3.0 5 votes vote down vote up
function getEstimatedMegaGas(api: ApiPromise, estimatedWeight: OrFalsy<BN>, withBuffer = true): BN {
  return (estimatedWeight || maximumBlockWeight(api)).div(BN_MILLION).addn(withBuffer ? 1 : 0);
}
Example #11
Source File: useWeight.ts    From contracts-ui with GNU General Public License v3.0 5 votes vote down vote up
function getDefaultMegaGas(api: OrFalsy<ApiPromise>, estimatedWeight?: OrFalsy<BN>): BN {
  if (api && estimatedWeight) {
    return getEstimatedMegaGas(api, estimatedWeight);
  }

  return maximumBlockWeight(api).div(BN_MILLION).div(BN_TEN);
}
Example #12
Source File: useWeight.ts    From contracts-ui with GNU General Public License v3.0 5 votes vote down vote up
useWeight = (estimatedWeight: OrFalsy<BN>): UseWeight => {
  // const estimatedWeightRef = useRef(estimatedWeight);
  const { api } = useApi();
  const [blockTime] = useBlockTime();
  const [megaGas, _setMegaGas] = useState<BN>(getDefaultMegaGas(api, estimatedWeight));
  const [isActive, setIsActive] = useState(!!estimatedWeight);

  const defaultWeight = useMemo((): BN => maximumBlockWeight(api), [api]);

  const setMegaGas = useCallback(
    (value?: BN | undefined) => {
      _setMegaGas(value || getDefaultMegaGas(api, null));
    },
    [api]
  );

  useEffect((): void => {
    if (!isActive) {
      _setMegaGas(getDefaultMegaGas(api, estimatedWeight));
    }
  }, [api, estimatedWeight, isActive]);

  return useMemo((): UseWeight => {
    let executionTime = 0;
    let percentage = 0;
    let weight = BN_ZERO;
    let isValid = false;

    if (megaGas) {
      weight = megaGas.mul(BN_MILLION);
      executionTime = weight.muln(blockTime).div(maximumBlockWeight(api)).toNumber();
      percentage = (executionTime / blockTime) * 100;

      // execution is 2s of 6s blocks, i.e. 1/3
      executionTime = executionTime / 3000;
      isValid = !megaGas.isZero() && percentage < 65;
    }

    return {
      defaultWeight,
      estimatedWeight,
      executionTime,
      isActive,
      isValid: !isActive || isValid,
      megaGas: megaGas || BN_ZERO,
      percentage,
      setIsActive,
      setMegaGas,
      weight,
    };
  }, [api, blockTime, defaultWeight, estimatedWeight, isActive, megaGas, setIsActive, setMegaGas]);
}
Example #13
Source File: InputFile.tsx    From contracts-ui with GNU General Public License v3.0 4 votes vote down vote up
export function InputFile({
  className = '',
  errorMessage,
  value: propsFile,
  isError,
  onChange,
  placeholder,
  onRemove,
}: Props) {
  const ref = createRef<DropzoneRef>();
  const [file, setFile] = useState<OrFalsy<FileState>>(propsFile);

  const onDrop = useCallback(
    (files: File[]): void => {
      files.forEach((file): void => {
        const reader = new FileReader();

        reader.onabort = NOOP;
        reader.onerror = NOOP;

        reader.onload = ({ target }: ProgressEvent<FileReader>): void => {
          if (target && target.result) {
            const name = file.name;
            const data = convertResult(target.result as ArrayBuffer);
            const size = data.length;

            onChange && onChange({ data, name, size });
            ref &&
              !propsFile &&
              setFile({
                data,
                name,
                size: data.length,
              });
          }
        };

        reader.readAsArrayBuffer(file);
      });
    },
    [ref, onChange, propsFile]
  );

  const removeHandler = useCallback((): void => {
    onRemove && onRemove();

    !propsFile && setFile(undefined);
  }, [onRemove, propsFile]);

  useEffect((): void => {
    if (file !== propsFile) {
      setFile(propsFile);
    }
  }, [file, propsFile]);

  return file ? (
    <div className={`${className} flex`}>
      <div className="p-6 border dark:bg-elevation-1 dark:border-gray-700 border-gray-300 inline-flex items-center rounded shadow">
        <DocumentTextIcon
          className="w-7 h-7 mr-2 text-gray-500 justify-self-start"
          aria-hidden="true"
        />
        <span className="dark:text-gray-300 text-gray-500 text-xs min-w-600 justify-self-start mr-20">
          {file.name} ({(file.size / 1000).toFixed(2)}kb)
        </span>
        {errorMessage && isError && (
          <span className="dark:text-gray-300 text-gray-500 text-xs min-w-600 justify-self-start mr-20">
            {errorMessage}
          </span>
        )}
        <XIcon
          className="w-5 h-5 mr-2 text-gray-500 justify-self-end cursor-pointer"
          aria-hidden="true"
          onClick={removeHandler}
        />
      </div>
    </div>
  ) : (
    <Dropzone multiple={false} onDrop={onDrop} ref={ref}>
      {({ getInputProps, getRootProps }) => {
        return (
          <div className={className} {...getRootProps()}>
            <label
              className="dark:text-gray-700 text-gray-400 font-normal py-2 px-4 border dark:border-gray-700 border-gray-200 rounded flex flex-col h-36 items-center cursor-pointer justify-center"
              htmlFor="file"
            >
              <svg
                xmlns="http://www.w3.org/2000/svg"
                className="h-8 mb-2 dark:text-gray-500"
                fill="none"
                viewBox="0 0 24 24"
                stroke="currentColor"
              >
                <path
                  strokeLinecap="round"
                  strokeLinejoin="round"
                  strokeWidth={2}
                  d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-8l-4-4m0 0L8 8m4-4v12"
                />
              </svg>
              <span className="text-sm dark:text-gray-500 text-gray-400">{placeholder}</span>
            </label>
            <input {...getInputProps()} data-cy="file-input" />
          </div>
        );
      }}
    </Dropzone>
  );
}
Example #14
Source File: Step2.tsx    From contracts-ui with GNU General Public License v3.0 4 votes vote down vote up
export function Step2() {
  const {
    data: { accountId, metadata },
    dryRunResult,
    stepBackward,
    currentStep,
    onFinalize,
    onFormChange,
  } = useInstantiate();

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

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

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

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

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

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

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

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

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

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

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

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

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

  if (currentStep !== 2) return null;

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

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