An Interest In:
Web News this Week
- April 19, 2024
- April 18, 2024
- April 17, 2024
- April 16, 2024
- April 15, 2024
- April 14, 2024
- April 13, 2024
Build on Flow | Learn FCL - 9. How to pass Optional and Path Arguments to Scripts
Overview
Last time we covered how to pass arguments in scripts, weve intentionally omitted Optionals and Paths arguments to lower the mental load. Those 2 are still important and quite common, so we will cover them in this tutorial.
After you follow and complete example covered in this post you will be able to:
- pass any Optional argument, regardless of its base type
- pass Path arguments
But first, lets look at what they are!
Theory
Optionals
are a bit like Schroedingers cat in programming: they can represent the presence or the absence of a value, when you check whats inside. Optionals have two cases:
- there is a value
- there is
nil
(nothing)
One use case where you might find this useful (that comes to my mind) is when you want to pass a Dictionary {String: String?}
and want to initialize some of the fields with empty values (for whatever reason )
Paths
arguments can be used when you want to use or access account storage in your script or transaction and doesnt want to hardcode that value, but rather make it more flexible.
Lets take a look at some common path /public/flowTokenVault
- this is a path to the publicly available Capability to access the FLOW token Vault resource. With this specific Capability you can use it to get reference to that resource to read its balance or deposit more tokens into it. Not all Capabilities are equal though! Some might give your more functionality and others less.
Back to our capability. If you take a look at it you can see that it consists of two parts:
- /public - this is called a
domain
. - /flowTokenVault - and this is an identifier
Technically /
character is a separator, but I think its easier to see it this way
There are only three valid domains:storage
,private
, andpublic
. In all of the scripts you will use public
domain - since it wont allow you to access private
and storage
areas of other accounts.
Lets try to pass both of those into some scripts!
Step 1 - Installation
Add "@onflow/fcl": "1.0.0"
as your dependency
Step 2 - Setup
Just like the last time we will import necessary methods and setup FCL:
// Import methods from FCLimport { query, config } from "@onflow/fcl";// Specify the API endpoint - this time we will use Mainnetconst api = "https://rest-mainnet.onflow.org";// Configure FCL to use mainnet as the access nodeconfig().put("accessNode.api", api);
Step 3 - Pass Path arguments
We will try to pass 3 different paths - PublicPath
, PrivatePath
and StoragePath
- each one for respective domain:
// Path Argumentsconst 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 });};
Please, note that t.Path
is a constant, even though we are passing object
Step 4 - Pass Optional Integer
To pass Optional, we need to wrap the type into t.Optional()
call. And thats it
// Optionalsconst 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 });};
Step 5 - Pass Other Optional Types
In similar fashion to our original post about arguments lets pass other Optional types all at once:
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);};
Step 6 - Pass Optional Array and Array of Optionals
The difference between those two is in target for t.Optional()
wrapper.
Heres 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 }); //};
And this one for optional array of 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 }); //};
Step 7 - Pass Dictionary with Optional values
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 });};
Have you noticed that script in last example returns Double Optional
Int??
? Thats because value atamount
key might not exist, so it will return usMaybe(Maybe(Int))
- you will need to unwrap it twice if you want to use it later in the code
Finally
Let's add an IIFE at the end of the file and populate it with methods we have just defined:
(async () => { console.clear(); // Path arguments await passPathArgument(); // Optional arguments await passOptionalIntegers(); await passMultiOptional(); await passArrayOfOptinalStrings(); await passOptionalArray(); await passDictionaryOfOptionals();})();
Some sparkling moments after you should see the output in the console log:
{result: Object} result: { domain: "private", identifier: "flowTokenVault" }{result: null}{result: "0x0000000000000001"}{result: "Hello"}{optionalArray: null}{result: "42"}
You did it - now those types are not a challenge to you!
Hope you find information in this post useful and will get back for more
Until next time!
Resources
- Full Source Code - https://codesandbox.io/s/dev-to-fcl-09-optional-arguments-vt0d11
- Cadence: Optionals - https://docs.onflow.org/cadence/language/values-and-types/#optionals
- Cadence: Paths - https://docs.onflow.org/cadence/language/accounts/#paths
- Cadence: Capabilities - https://docs.onflow.org/cadence/language/capability-based-access-control
Other resources you might find useful:
- Flow Docs Site-https://docs.onflow.org/- More detailed information about Flow blockchain and how to interact with it
- Flow Portal-https://flow.com/- your entry point to Flow
- FCL JS-https://github.com/onflow/fcl-js- Source code and ability to contribute to the FCL JS library
- Cadence - https://docs.onflow.org/cadence/ - Introduction to Cadence
- Codesandbox-https://codesandbox.io- An amazing in-browser IDE enabling quick prototyping
Original Link: https://dev.to/onflow/build-on-flow-learn-fcl-9-how-to-pass-optional-and-path-arguments-to-scripts-3cgn
Dev To
An online community for sharing and discovering great ideas, having debates, and making friendsMore About this Source Visit Dev To