DEV Community

EgorMajj
EgorMajj

Posted on

Создаем на Flow | Изучаем FCL — 9. Как передавать скриптам аргументы Options и аргументы Path

Краткий обзор

В прошлый раз, когда мы рассказывали о том, как передавать аргументы в скриптах, мы намеренно опустили аргументы Optionals и Paths, чтобы снизить умственную нагрузку. Эти два аргумента по-прежнему важны и довольно часто встречаются, поэтому мы рассмотрим их в этом уроке.

После того, как вы выполните все примеры, описанные в этом посте, вы сможете:

  • передавать любой аргумент Optional, независимо от его базового типа
  • передавать Path аргументы

Но сначала давайте посмотрим, что это такое!

Теория

Optionals - это что-то вроде кота Schroedinger в программировании: они могут представлять наличие или отсутствие значения, когда вы проверяете, что находится внутри. У опций есть два случая:

есть значение
есть nil (ничего).

Один из примеров использования, где вы можете найти это полезным (который приходит мне на ум) - это когда вы хотите передать Dictionary {String: String?} и хотите инициализировать некоторые строки пустыми значениями (по какой-либо причине 🤷♂️).

Paths Аргументы могут быть использованы, когда вы хотите использовать или получить доступ к хранилищу учетных записей в своем скрипте или транзакции и не хотите жестко кодировать это значение, а хотите сделать его более гибким.

Рассмотрим некоторые распространенные Path /public/flowTokenVault - это path к управлению доступом ресурса FLOW token Vault. С помощью этой специфической способности вы можете получить ссылку на этот ресурс, чтобы посмотреть его баланс или пополнить его токенами. Однако не все возможности одинаковы! Некоторые могут дать вам больше функциональности, а другие - меньше.

Вернемся к нашей функции. Если вы посмотрите на нее, то увидите, что она состоит из двух частей:

  • /public - это называется domain.
  • /flowTokenVault - а это идентификатор.

Технически символ / является разделителем, но я думаю, что проще увидеть это так 😉.

Существует только три допустимых domain: storage, private и public. Во всех скриптах вы будете использовать public domain - поскольку он не позволит вам получить доступ к private областям и областям storage других учетных записей.

Давайте попробуем передать оба этих domain в некоторых скриптах! 💪

Шаг 1 - Установка

Добавьте "@onflow/fcl": "1.0.0" в качестве зависимости

Шаг 2 - Настройка

Как и в прошлый раз импортируем необходимые методы и настраиваем FCL:

// Import methods from FCL
import { query, config } from "@onflow/fcl";

// Specify the API endpoint - this time we will use Mainnet
const api = "https://rest-mainnet.onflow.org";

// Configure FCL to use mainnet as the access node
config().put("accessNode.api", api);
Enter fullscreen mode Exit fullscreen mode

Шаг 3 - Передача Path аргументов

Мы попытаемся передать 3 различных Path - PublicPath, PrivatePath и StoragePath - каждый для соответствующего domain:

// Path Arguments
const passPathArgument = async () => {
  const cadence = `
    pub fun main(public: PublicPath, private: PrivatePath, storage: StoragePath): PrivatePath{
      // we can return any value, but let's return one of the Paths to see
      // how FCL decodes it into value
      return private
    }
  `;

  // Since we are not gonna use any of those for actual data access
  // we can construct any paths we like
  // this one will encode "/public/flowTokenVault"
  const publicPath = {
    domain: "public",
    identifier: "flowTokenVault"
  };

  // encode "/private/flowTokenVault"
  const privatePath = {
    domain: "private",
    identifier: "flowTokenVault"
  };

  // encode "/storage/flowTokenVault"
  const storagePath = {
    domain: "storage",
    identifier: "flowTokenVault"
  };

  // Notice that t.Path is not a function, but a constant!
  const args = (arg, t) => [
    arg(publicPath, t.Path),
    arg(privatePath, t.Path),
    arg(storagePath, t.Path)
  ];
  const result = await query({ cadence, args });
  console.log({ result });
};
Enter fullscreen mode Exit fullscreen mode

Обратите внимание, что t.Path является постоянным, несмотря на то, что мы передаем объект 🤪.

Шаг 4 - Передача Optional целому числу

Чтобы передать Optional, нам нужно обернуть тип в вызов t.Optional(). Вот и все 😊.

// Optionals
const passOptionalIntegers = async () => {
  const cadence = `
    pub fun main(a: Int?): Int?{
      return a
    }
  `;

  // We will set value of our Int argument to null to check that script works correctly
  const a = null;
  const args = (arg, t) => [arg(a, t.Optional(t.Int))];

  const result = await query({ cadence, args });
  console.log({ result });
}; 
Enter fullscreen mode Exit fullscreen mode

Шаг 5 - Pass других Optional типов

По аналогии с нашей первоначальной статьей об аргументах, давайте передадим другие типы Optional все сразу:

const passMultiOptional = async () => {
  const cadence = `
    pub fun main(a: String?, b: Bool?, c: UFix64?, d: Address?): Address?{
      return d
    }
  `;

    // it's perfectly fine to pass non-nil values alongside "empty"
  const a = "Hello";
  const b = null;
  const c = null;
  const d = "0x01";

  // Note the types are the same as we specify in Cadence code
  const args = (arg, t) => [
    arg(a, t.Optional(t.String)),
    arg(b, t.Optional(t.Bool)),
    arg(c, t.Optional(t.UFix64)),
    arg(d, t.Optional(t.Address))
  ];

  const result = await query({ cadence, args });
  console.log({ result });

  showResult("multiple", result);
};
Enter fullscreen mode Exit fullscreen mode

Шаг 6 - Pass Optional Array и Array of Optionals

Разница между ними заключается в цели для обертки t.Optional().

Вот array of Optionals:

const passArrayOfOptinalStrings = async () => {
  const cadence = `
    pub fun main(a: [String?]): String?{
      return a[0]
    }
  `;

  const a = ["Hello", null];
  // Type of the argument is composed of t.Array, t.Optional and t.String
  const args = (arg, t) => [arg(a, t.Array(t.Optional(t.String)))];
  const result = await query({ cadence, args });
  console.log({ result }); //
};
Enter fullscreen mode Exit fullscreen mode

А этот для опционального массива Strings:

const passOptionalArray = async () => {
  const cadence = `
    pub fun main(a: [String]?): String?{
      if let arr = a {
        return arr[0]
      }

      return nil
    }
  `;
  const a = null;
  // This time we will wrap our array in "t.Optional()" call
  const args = (arg, t) => [arg(a, t.Optional(t.Array(t.String)))];
  const optionalArray = await query({ cadence, args });
  console.log({ optionalArray }); //
};
Enter fullscreen mode Exit fullscreen mode

Шаг 7 - Передача Dictionary с Optional значениями

const passDictionaryOfOptionals = async () => {
  // In this example we will pass a Cadence Dictionary as argument
  // keys will be of type "String" and values will be Optionals of type "Int?"
  const cadence = `
    pub fun main(a: {String: Int?}): Int??{
      return a["amount"]
    }
  `;

  // Dictionaries should be represented as array of key/value pairs of respective types
  // Note that we shall pass numeric value as string here
  const a = [{ key: "amount", value: "42" }];
  // Dictionary type is composed out of t.Dictionary, t.String and t.Int for our case
  const args = (arg, t) => [
    arg(a, t.Dictionary({ key: t.String, value: t.Optional(t.Int) }))
  ];

  const result = await query({ cadence, args });
  console.log({ result });
};
Enter fullscreen mode Exit fullscreen mode

💡 Вы заметили, что скрипт в последнем примере возвращает Double Optional Int(?). ? Это потому, что значение по ключу amount может не существовать, поэтому он вернет нам Maybe(Maybe(Int)) - вам нужно будет развернуть его дважды, если вы хотите использовать его позже в коде 😉

Заключение

Давайте добавим IIFE в конец файла и заполним его методами, которые мы только что определили:

(async () => {
    console.clear();

    // Path arguments
  await passPathArgument();

    // Optional arguments
  await passOptionalIntegers();
  await passMultiOptional();
  await passArrayOfOptinalStrings();
  await passOptionalArray();
  await passDictionaryOfOptionals();
})();
Enter fullscreen mode Exit fullscreen mode

Через несколько 🎇 мгновений после этого вы должны увидеть вывод в журнале консоли:

{result: Object}
    result: {
        domain: "private",
        identifier: "flowTokenVault"
    }
{result: null}
{result: "0x0000000000000001"}
{result: "Hello"}
{optionalArray: null}
{result: "42"}
Enter fullscreen mode Exit fullscreen mode

Вы сделали это - теперь эти типы не являются для вас испытанием! 💪

Надеюсь, информация в этом посте будет полезной, и вы вернетесь за новыми материалами 😉.

До следующего раза! 👋

Информационные ресурсы

Другие источники, которые могут быть вам полезны:

  • (ENG) | Документация Flow - https://docs.onflow.org/ - более детальная информации о блокчейне Flow и как взаимодействовать с ним
  • (ENG) | Flow Portal - https://flow.com/ - your entry point to Flow
  • (ENG) | FCL JS - https://github.com/onflow/fcl-js - Исходный код и возможность поучаствовать в разработке библиотеки FCL JS library
  • (ENG) | Cadence - https://docs.onflow.org/cadence/ - Введение в язык программирования Cadence
  • Codesandbox - https://codesandbox.io - Замечательная среда разработки и прототипирования прямо в вашем браузере

Top comments (0)