2 Glow Tutorial
Welcome to Glow’s tutorial.
Glow is a domain-specific language for writing safe DApps (Decentralized Applications). Here you will learn everything about this mighty language, and its associated toolset, to perform feats previously inaccessible to mere mortals!
2.1 Intro
This tutorial has been designed with multiple layers of complexity, in order to best guide you, regardless of your level of proficiency in programming and computer science: You can re-read it as you get better at using Glow. This tutorial has been written by both nearly total beginners, and computer science experts, so that Glow can be learned without confusion.
If that’s not enough, you can always:
For community help, join our Discord channel (invite).
For commercial support, email [email protected].
2.1.1 Level 1: I am new to computer programming
Great! Your presence here means our product is becoming mainstream.
For now, though, Glow is a bit tricky to start programming, but in the future, we plan to make tutorials that will take you from zero knowledge to a point where you can code DApps with Glow without any uncertainty. We want to make Glow as accessible as possible, and we’ll do everything for you to reach this goal.
In the meantime, you can browse the Internet to learn the two prerequisites for Glow-programming:
The general notions of computer science and app-development.
A basic understanding of how blockchain-related programming works.
You can still read this documentation for business purposes and skip the parts that contain code.
2.1.2 Level 2: I can make standard apps
You’re a developer with knowledge of the production of standard apps. You know how to make one for your users, but you lack the knowledge and experience in the field of DApps: Glow comes with many typical smart-contracts that you can use in your DApps.
You just have to invoke one of the Glow programs in our standard library, with parameters suitable to your use-case, and our software will let you safely interact with the blockchain.
You’ll be sure that your DApp’s transactions are secure, so that you only have to take care of what matters the most in any app: its general design, its business logic, its front-end, etc.
While you won’t need to program in the Glow language, you may still read this tutorial to understand what Glow does for you and how it works, so you can fit the functionality it provides into the architecture of your application. Thus you can ultimately use Glow and its runtime as an efficient tool that will save you time and money, a lot of a worrying uncertainty about the risks you would otherwise have to face while building your DApp.
2.1.3 Level 3: I can make DApps, and want to make my own smart-contracts
You have read this tutorial and tried Glow for a while, or you are already a bit experienced in blockchain-related programming.
This documentation will allow you to make your own smart-contracts: you will develop your own versions of our tools, for your own unique vision of smart-contracts. The team behind Glow can audit and certify your smart-contracts for a fee, if you want to make sure they are safe, and want your potential users to trust it, too.
Each chapter of this tutorial links to sub-documents for Level-3 users. Each time you want to be more autonomous and make the best use of Glow, those links will give you advanced tips about what our community and development team understood over time.
It’ll save you precious tinkering time, and you’ll be able to grasp Glow (and DApps) like never before.
2.1.4 Level 4: I want to help develop Glow and understand all the details
A contributor, are we? Well, welcome backstage: each chapter of this tutorial contains sub-documents for level-4 users.
These sub-documents can contain either the source code of Glow (written in other languages) or details about the thinking process we went through (you’ll find some high-level mathematical proofs, links to our previous versions, and many other things).
In the end, these documents will allow you to contribute to Glow, make your own version of it, or just audit it and know it as well as we do.
Feel free to share your progress with the community.
2.2 Why use Glow?
Regular apps and computer programs are generally safe and reliable when used by only one person: i.e. solo video games, text editors, calculators, graphic design softwares, or anything, really...
But when you have to interact with other people with one of today’s regular apps, it needs to be regulated by a centralized entity: a state, a company, or a person. This entity (i.e. AirBnB, Facebook, Uber, Amazon, any bank account or wallet, sending emails, etc.) will use servers physically located in a data center, to ensure the safety of the interactions. This entity, or people who manage to coerce it (governments and mafia), or penetrate it (hackers and spies), can control or disrupt the users’ experience: from charging a monopoly rent to censoring dissenting activities, from spying on users to tampering with data, from spamming the users with unwanted advertising to trying to influence them with propaganda, false or biased news, omissions and distractions. Sometimes, the users are victims of the central entity’s negligence, incompetence, or change of mind, that causes the service to be cancelled, disrupted, corrupted, or just slow and buggy, and never fixed.
An app that runs without being controlled by any single entity or consortium of colluding entities that can unaccountably collude against users is called a DApp, which stands for Decentralized Application, and is pronounced either "dap" or "D-app".
A DApp is distributed around all the users of a network, and compared to its centralized ancestor, it has many advantages:
Uncensorable, ad-less, bias-less, spam-less social networks.
Peer-to-peer services where individual service providers are paid more. (because they don’t pay monopoly rent to a centralized server).
Increased safety of your asset transfers.
Complete traceability of an asset, for supply chain managers, stock-management, or even lawyers.
Enhanced privacy.
Problem
Compared to centralized programs, DApps are both much harder to write and much less tolerant to mistakes.
DApps are harder to write, because they inherently involve multiple untrusting participants over asynchronous networks; when designing protocols, you must therefore make sure that the incentives of all participants are aligned at all times.
DApps are less tolerant to mistakes, because active adversaries constantly seek to take advantage of any mistakes to steal your assets, and there is no central authority to enforce your rights if that happens (or to violate them ordinarily); thus you cannot afford any single bug in the parts of your apps that deal with immutable decentralized ledgers.
Hundreds of millions of dollars worth of assets have been lost to various mistakes made in DApps, already. Even seasoned experts make simple manipulation mistakes and lose tens of thousands of dollars.
Solution
To make DApps more mainstream, the world needed a toolset to automate all the critical parts of a DApp and make them safe.
This is precisely what Glow is: it drastically simplifies the way a DApp is programmed, to make it safer.
2.3 What is Glow for?
2.3.1 A programming language for DApps
Glow is a programming language used to make DApps. It comes with a wide set of tools.
Glow’s three main specificities are:
Safety: each newly implemented function is thoroughly audited so that a programmer using the Glow language or its associated toolset won’t have to worry about securing interactions between users.
User-friendliness: we want to make DApps mainstream, and Glow’s development team always aims at making it obvious what a DApp does or doesn’t, so users can ascertain that it indeed matches their expectations.
Portability to any blockchain: applications written in Glow can produce run on any blockchain, so you unlike with previous tools, you don’t have to learn all the tooling specific to a single blockchain only to realize later the users you want will be on another blockchain. A same DApp will be able to use the resources of multiple blockchains at once, and meet the users where they are and wherever they will be.
In other words: what usually takes a huge amount of lines of code, and many experts in various fields, has been automated. Some people will use contracts pre-made in Glow, some others will make their contracts with a very safe language.
2.3.2 What Glow can and can’t do
Glow is a language dedicated to the critical parts of DApps: interactions between multiple participants who do not trust each other, to exchange digital assets registered on decentralized ledgers, according to rules verifiable by computers.
The role of the DApp is to create a sufficient trust between the participants for them to actually partake in an interaction in which they wouldn’t otherwise have dared participate, based on their trust in the ledgers that maintain their digital assets, based on their trusting how these ledgers supports "smart contracts" that will enforce the rules of the interaction, and based on their understanding of the rules of the interaction and agreement to them.
The role of Glow is to allow the participants to think of this interaction in terms of the asset transfers that matter to them, while taking care of all the difficult tasks required to translate this interaction in terms of messages exchanged on asynchronous digital networks.
At the moment, Glow isn’t meant to be used to program every type of software.
Just like some languages are dedicated to specialized tasks
(e.g. R for data science and statistics), Glow’s main focus is safe DApps,
including the underlying smart contracts, but not limited to them—
For that reason, every time we add a new feature, we carefully check if its addition is safe in the whole Glow ecosystem. Maybe one day you will be able to program complete apps, full video games and everything in Glow, but for the moment, we focus on Glow’s specialty, so that DApps developed with Glow stay safe.
2.3.3 More information
2.3.3.1 Official pages and documents
Official website: https://glow-lang.org
Social media pages:
Twitter: @MutualKnowledge
Facebook: facebook.com/MuKnSys/
Telegram: t.me/mukn_io
Linkedin: linkedin.com/company/mukn-io/
Youtube: www.youtube.com/playlist?list=PLiEa4i6H-qcdosr5x1jPkGJRUVPB1GOlL
Discord: https://discord.com/channels/655606984514469899/655606984967585832 (invite)
And of course, to get more information about Glow, you can read our whitepaper.
2.3.3.2 Team and license
Glow is Free and Open Source and will forever remain so.
Glow is distributed under the Apache License, version 2.0 (see the file LICENSE).
Copyright © 2019 Mutual Knowledge Systems, Inc. All rights reserved.
US-based company Mutual Knowledge Systems, Inc. has been developing Glow, keeps developing it, yet doesn’t want to have a legal monopoly over it: we just want to keep it accessible for all to see and audit, to use and adapt, to fix and improve, so you can trust it to indeed always be the best language in which to write DApps.
Check our website to discover the human beings behind the code.
2.3.3.3 GitHub repo
You can check our GitHub repository to know the code as well as we do.
2.3.3.4 Our history
Check our history to learn more about how we arrived there.
We also thoroughly keep track of every source of reliable information about Glow.
2.3.3.5 Glow’s predecessor
For the sake of history, you can learn more about our previous attempt at building a safe and reliable language for DApp-development: Alacrity.
2.3.3.6 Conceptual Basis
We compiled and extensive list of what you should read to understand our thought-process during the development of Glow.
2.3.4 Environments
2.3.4.1 Use Glow in any browser
TODO: In the near future, our code will run on any browser on any desktop or laptop or mobile device, with a nice user interface. But this is still work in progress.
2.3.4.2 Use Glow locally on Linux and macOS
At the moment, Glow can run on Linux and macOS.
Any Linux distribution will do: we use the Nix package manager. Nix can run for users on top of any Linux distribution (not just NixOS), and also runs well on macOS. Nix notably builds software in a deterministic way, so that if it works for us it will work for you, and if you experience a bug, we can reproduce it, too, and fix it.
TODO: We will soon add support for Windows. Nix doesn’t yet run out-of-the-box on Windows; given sufficient resources, it could be made to. Glow can also be built without Nix, though making that run on Windows too will require resources. Instead, we plan to have Glow target the JavaScript platform, and be able to run on Windows that way.
2.4 Getting started
2.4.1 Simplified install on Linux or macOS
2.4.1.1 Install Glow with only one command line
To install Glow as a user or developer, go to a terminal window (or any app on your system that allows you to enter shell commands).
Once there, type or copy/paste the following command line:
curl -L https://glow-lang.org/install/glow-install | sh |
If you use Linux or macOS on x86_64, all the binary packages for the software we use will be cached, and the installation should only take a few minutes, depending on the speed of your Internet connection. Note that this software may take above 2GB of memory, so make sure you have enough space available on disk.
If you use another platform, your computer may recompile a lot of code from source before the software is ready to run, especially the first time over. Let it run overnight.
Safety
This installation script first installs the Nix package manager, which may require you to manually type yes, or y and/or type the administrator password around the beginning, to authorize parts of the installation. It is a normal part of the process.
Of course we trust the installation code, but you shouldn’t until you audit it, and so you would be more prudent to run it inside a virtual machine. For extra security, you might want to use Qubes OS.
Why the installation is that long (levels 3 and 4)
The reason the installation is that long is that you are using a platform for which we don’t have precompiled binary packages, and so the installation is going to recompile the entire compiler suite, starting with Gambit Scheme.
If you are using a computer with a supported target architecture, and it’s recompiling, then there must be a bug in our release discipline. Please contact us about it.
Configuring Nix to use our repository
For alpha quality releases (the only ones at this moment), we offer this nixpkgs channel:
export NIX_PATH=nixpkgs=http://github.com/muknio/nixpkgs/archive/alpha.tar.gz |
For the latest development code on the bleeding edge (which can be broken at times), we offer this nixpkgs channel:
export NIX_PATH=nixpkgs=http://github.com/muknio/nixpkgs/archive/devel.tar.gz |
Building from source
Once you have installed Glow and all its dependencies via Nix, and have downloaded its source code, you can re-build it from source
nix-build |
Or you can install the resulting software with
nix-env -iA . |
2.5 Trying it out with Docker (levels 3 and 4)
When we have a stable release, we’ll directly provide an image mukn/glow:alpha on Docker.
In the meantime, you can build your own with:
docker build -t mukn/glow -f scripts/Dockerfile |
2.6 Install Glow the hard way on other systems (levels 3 and 4)
If you don’t use either Linux or macOS, and can’t use Docker, you will have to build and install Glow the hard way: installing GCC (usually easy), and a bunch of libraries (tedious), on top of that Gambit Scheme with the correct options (requires care), on top of it Gerbil Scheme, on top of it all Glow.
If you really want to try it this way, you can check our hardcore installation file.
2.7 Language Overview
Glow is a domain-specific language for DApps, Decentralized Applications.
The language syntax is based on that of JavaScript, with some inspiration from ReScript where we have to diverge from JavaScript. While it should feel familiar to you if you know JavaScript, there are many differences underneath designed to keep your DApps safe:
The language is statically typed. Its type system is in the same general style as ReScript or TypeScript, yet differs in many details, wherein we optimize our design for the safety of DApps.
Though the syntax looks imperative, it is a functional language underneath. In particular, you cannot modify bindings to existing variables, you can only have new variables shadow old variables. You also cannot side-effect data structures, only create new data structures that shadow the old data structures as those in consideration.
Many features are currently missing, such as loops or recursion, that will be added slowly as the need arises.
If you are used to programming in imperative languages, you will also find common concepts.
For programming language buffs: DApps are asynchronous interactions between multiple mutually-untrusting participant manipulating digital assets on decentralized ledgers, according to rules verifiable by blockchain smart contracts. Semantically, Glow is an applicative language with a pure functional programming core extended with a few primitives and annotations making it suitable for for multiparty computation. It has a static type system based on MLsub.
If you are a seasoned developer, you can check our less-detailed and straight-to-the-point grammar, our Glow Language Grammar. Otherwise the next chapters are designed to make you grasp it quickly.
2.8 Fundamentals: Hello world!
Unlike most languages, including most languages supposedly dedicated to specifying DApps or just their smart contracts, Glow is a language focused on interactions between multiple participants. Hence, there is no typical "hello world!" program like in most languages, but there is something alike: a "hello world!" for two...
@interaction([A, B])
@A let ha = "Hello, B, I am A. How do you do?";
publish! A -> ha;
@B let hb = "Hello, A. I am B. How do YOU do?";
publish! B -> hb;
};
This is not a very useful DApp, but then neither is printing "Hello, world". For a minimal useful DApp, see Buying a Signature below.
Interactions are specified using annotations, that begin the "at-sign" (a.k.a. arobase): @
If you remove the annotations, it looks like a regular JavaScript or ReScript program, except with those special publish! statements.
(Also, note that white spaces and interlines don’t matter. We didn’t implement indentation-based structure, and don’t intend to in the short-run. It is too easy to introduce subtle bugs with such semi-invisible structure; we prefer bugs to remain painfully obvious, instead.)
The first line of this code specifies through an annotation that the following function will be an interaction between two participants the roles of which are called A and B.
You can see that semicolons are used to end statements. They can be used to end every expression, but are mandatory only for statements.
The second line defines the interaction function.
The third and fifth lines define two private variables respectively named ha and hb using the keyword let, each bound to a different byte string. The former is initially private to A only, while the latter is initially private to B only.
The fourth and sixth lines use the publish! statement to specify that the respective sentences ha and hb will be sent respectively on behalf of users A and B.
Note that these instructions will be executed line by line, so the dialog will happen like a real one.
2.9 Buying a Signature
The simplest useful DApp you can write is one to buy and sell a signature. This is what our example DApp buy_sig below does.
Its practical applications include:
"Swaps" where you sign a message for use on another blockchain.
Rental where you sign a message that grants you access to some digital resource.
"Diploma", certification or other affidavit—
also for purely digital goods.
However, for applications that involve real-world goods and services, you will want a slight modification of buy_sig at the end of which the price is deposited into another DApp: an escrow that allows a trusted third-party or decentralized oracle to be used as an arbitrator in case of later dispute between the two participants.
2.9.1 Writing the DApp
@interaction([Buyer, Seller])
deposit! Buyer -> price;
@publicly!(Seller) let signature = sign(digest);
withdraw! Seller <- price;
};
This contract starts with a special mandatory line #lang glow to indicate that it is a glow program indeed.
Then we define a function buySig with two parameters digest and price, in a syntax familiar to JavaScript, TypeScript or ReScript programmers. However, this definition is preceded by an annotation @interaction([Buyer, Seller]) that indicates that this function involves a blockchain interaction with two participant roles: A first role called Buyer, and a second role called Seller.
This interaction involves two steps, each step being a blockchain transaction involving one participant and the on-chain smart contract.
In the first step, the Buyer deposits the agreed-upon price in escrow into the smart contract, with this statement:
deposit! Buyer -> price;
In the second step, the Seller publishes their signature, and after the contract verifies the signature, withdraws the price:
@publicly!(Seller) let signature = sign(digest);
withdraw! Seller <- price;
Note that the line @publicly!(Seller) let signature = sign(digest); above is equivalent to the three statements below:
@verifiably!(Seller) let signature = sign(digest);
publish! Seller -> signature;
verify! signature;
That is, in a first, let, statement, the Seller, in the privacy of their personal computer, signs the (digest of the) message, using their secret key. Then, in a second, publish! statement, the Seller publishes this signature onto the consensus. Finally, in a third, verify! statement, everyone verifies that the signature is valid. If the signature isn’t valid, the step fails, the blockchain transaction is rejected by the smart contract, and it is as if the seller didn’t do a thing (they can try again with a valid signature).
How does the verify! statement know what to verify? Because the let was annotated with @verifiably!, that records how to verify the definition. Thus, the verification will be as if the programmer had written:
require! isValidSignature(Seller, signature, digest);
Except that you don’t need to audit that line, because the compiler did it for you (you may still want to audit the compiler instead). This is especially true as verifications can become involved, and as the formulas to be verified may evolve through time, and manual propagation of changes is sure to introduce subtle bugs sooner or later. The use of @verifiably! thus makes for shorter, more reliable DApps.
How do we (the programmers, and the compiler) know there exactly two steps? Because that’s the number of changes in which participant is active: in the first step, everything can be done by the Buyer in interaction with the consensus. Then everything can be done by the Seller in interaction with the consensus. This is a different participant, and therefore requires a separate transaction. Each step will span as many statements and expressions as can be done without changing the active participant. Statements that are done solely by the consensus, such as the final withdrawal, will take place without changing the current active participant, in the same transaction step.
In practice, the two participants must agree off-chain on the terms of the interaction. Then, the first participant, in this case the Buyer, creates the on-chain smart contract as part of enacting their first transaction step. They then communicate the contract address to the Seller as part of an off-chain handshake. The Seller verifies that the terms of the handshake indeed correspond to a previous agreement, and then enacts their transaction. At the end, the contract concludes, the Buyer can read the signature, and the Seller has been paid.
What if the Buyer never creates the contract? Then they time out, and the Seller drops the interaction from their active set. All they achieved was wasting their own time.
What if the Seller never gets the handshake or otherwise fails to publish the signature? Then they time out, and the Buyer can invoke the contract to get their money back. All that happened is the Buyer wasted some time and some transaction fees to create and destroy the contract.
2.9.2 Setting up identities to run the DApp
Having followed the above section, you should have a DApp written in Glow. Before we run it, we need to have a buyer and seller who can carry out transactions on the blockchain. Thus we will define two individuals: Alice (buyer) and Bob (seller), and assign identities to them.
glow generate-identity -N alice |
Generated identity: Alice [ 0x4c371dA6E338F19B77BC78498DaFcFB05E8bd2Ac ] |
|
./glow generate-identity -N bob |
Generated identity: Bob [ 0x0C7A123580a2A6E40b053b2dE913fd0e2B8b91e9 ] |
We also need to ensure they have the funds to perform computations and transactions on the EVM:
glow faucet -t alice |
glow faucet -t bob |
2.9.3 Generating a document digest for the DApp
Recall that the buyer wants to get a digest signed by the seller:
We can generate a new digest for this purpose:
echo "some text" > test.txt |
glow digest test.txt |
0x19f1f7dac2cd7ca5db03cd70f56b1d041841c600bc1313eb14474923116bb49f |
| |
└--- We copy this to provide as input to the DApp function |
in later sections. |
2.9.4 Deploying the DApp
Next, we want to deploy our contract on the testnet. Glow locates DApps with the GLOW_PATH variable. To see which PATHs are included, use:
glow show-glow-path |
Include the directory containing the DApp in GLOW_PATH:
export GLOW_PATH=$GLOW_PATH:<directory-containing-my-contract> |
You can now deploy the DApp on the Devnet:
> glow start-interaction |
Connecting to the Cardano EVM Devnet at https://rpc-evm.portal.dev.cardano.org/ ... |
|
Choose application: |
1) buy_sig # ---┬--- Our Standard Library DApps |
2) coin_flip # ---┤ |
3) rps_simple # ---┘ |
4) my_contract # ------- The DApp you wrote |
Enter number |
> 4 |
You will then choose the identity of the individual (Alice) deploying the contract, and the address of the Buyer (Alice) and Seller (Bob):
Choose your identity: |
1) alice - 0x4c371dA6E338F19B77BC78498DaFcFB05E8bd2Ac |
2) bob - 0x0C7A123580a2A6E40b053b2dE913fd0e2B8b91e9 |
Enter number |
> 1 |
Choose your role: |
1) Buyer |
2) Seller |
Enter number |
> 1 |
Assign roles |
Select address for Seller: |
1) alice - 0x4c371dA6E338F19B77BC78498DaFcFB05E8bd2Ac |
2) bob - 0x0C7A123580a2A6E40b053b2dE913fd0e2B8b91e9 |
Enter number |
> 2 |
We will continue to provide this as input to the DApp function:
Define parameters |
Enter digest |
> 0x19f1f7dac2cd7ca5db03cd70f56b1d041841c600bc1313eb14474923116bb49f |
| |
└--- We paste the document digest from earlier. |
|
> Enter price |
> 1000000 |
Finally we declare the max initial block, which should be a block after the current one.
Max initial block [ Current block number is 107850 ] |
> 107900 |
We will then get a command which the buyer can use to interact with the smart contract. Copy the command for use in the later sections.
One line command for other participants to generate the same agreement: |
glow start-interaction --agreement '{...}' |
|
Executing code block begin0 ... |
(add-to-deposit price) |
(@debug-label dlb1) |
2.9.5 Interacting with the DApp
Recall that earlier we defined alice to be the buyer. As such, alice will call the contract. To do so, start a new terminal window and paste the one-line command above. Note that we append ‘–database alice‘ to the end of the contract. This keeps the data of alice and bob separate.
glow start-interaction --agreement '{...}' --database alice |
Connecting to the Cardano EVM Devnet at https://rpc-evm.portal.dev.cardano.org/ ... |
|
Choose your identity: |
1) alice - 0x4c371dA6E338F19B77BC78498DaFcFB05E8bd2Ac |
2) bob - 0x0C7A123580a2A6E40b053b2dE913fd0e2B8b91e9 |
3) charles - 0x47312084A1026E2B5ae7E3A7ef6f328421740961 |
Enter number |
> 1 |
Choose your role: |
1) Buyer |
2) Seller |
Enter number |
> 1 |
Executing code block begin0 ... |
(add-to-deposit price) |
(@debug-label dlb1) |
Next, in a new terminal, bob will call the contract, again appending ‘–database bob‘ to keep their data separate.
glow start-interaction --agreement '{...}' --database bob |
|
Choose your identity: |
1) alice - 0x4c371dA6E338F19B77BC78498DaFcFB05E8bd2Ac |
2) bob - 0x0C7A123580a2A6E40b053b2dE913fd0e2B8b91e9 |
Enter number |
> 2 |
Choose your role: |
1) Buyer |
2) Seller |
Enter number |
> 2 |
|
Paste below the handshake sent by the other participant: |
You will then obtain a handshake agreement in alice’s terminal, to be sent to the seller off-chain. In our case we will simply copy this agreement from our terminal for later use.
Send the handshake below to the other participant: |
{"agreement":{...}} -- copy this from alice's terminal |
We will paste this in bob’s terminal, who will sign and display the signature:
Paste below the handshake sent by the other participant: |
{"agreement":{...}} -- paste this in bob's terminal |
Executing code block begin0 ... |
(expect-deposited price) |
(@debug-label dlb1) |
|
Executing code block cp0 ... |
(set-participant Seller) |
(def signature (sign digest0)) |
(add-to-publish 'signature signature) |
(def tmp (@app isValidSignature Seller digest0 signature)) |
(require! tmp) |
(@debug-label dlb2) |
(participant:withdraw Seller price) |
(return (@tuple)) |
(@label end0) |
|
buy_sig#buySig interaction finished |
Final environment: |
Buyer => (address<-0x "0x4c371dA6E338F19B77BC78498DaFcFB05E8bd2Ac") |
Seller => (address<-0x "0x0C7A123580a2A6E40b053b2dE913fd0e2B8b91e9") |
digest => (bytes<-0x "0x16c5659f6e3c70f0c53ac5abf3977e658093f1f5880bd478de8d3a87c92d9607") |
price => 1000000 |
signature => (<-json Signature "<signature>") |
We have now successfully created, deployed and ran an interaction with a Glow DApp! Congratulations if you’ve made it this far!