Developer Christoph Verdo talks about the online course ',' which he recently completed.

Tell us a little about yourself. What attracted you to this course?
I have been working in web development for about 15 years, primarily as a freelancer.
While developing a long-term registration web application for developing countries commissioned by a banking group, I encountered the challenge of integrating blockchain certification into it. At that time, I didn't know much about blockchain certification, although I was already interested in crypto technologies—mainly as an investor.
Ultimately, this feature wasn't implemented, but reflecting on the fact that organizations and banks are interested in such solutions for their applications, I began to study the issue and soon launched the project .
. I developed its beta version, which is already available on the mainnet. At that time, there was no [Waves programming language] Ride, and I was doing everything in the simplest way using transfer transactions with embedded JSON. But the main goal was to add more advanced functionality after the launch of Ride. And this is the main reason I joined the course: the next stage of the project's development involved creating a decentralized application (dApp).
What aspects of the course did you find the easiest and which the most challenging?
The easiest part was that we had enough time for all assignments. The essence of the course is to learn something, not to compete with each other. The explanations were very accessible, and the illustrations—simple but comprehensive. This helped visualize and understand different topics.
When completing assignments, we were encouraged to think independently and sometimes study things on our own. This is the best way to learn something and grasp the ideas discussed in class.
A few times I didn't fully understand the theoretical part until I started writing code to complete the assignment. We were not allowed to do 'copy/paste'; we had to write all the code ourselves, and this also helped clarify everything.
The most challenging part was that the questions in the multiple-choice assignment were not always clear. My English is not perfect, and the questions were written by someone who is not a native speaker, so there were instances of misunderstanding.
Perhaps the portion of the course dedicated to oracles and NFTs could have been more detailed. However, the main goal of the course is to engage developers. Then, to fully understand all its aspects, one would need to spend some time experimenting and practicing.
Could you tell us more about the project you worked on throughout the course – 'Coupon Bazaar'? Can we also see some code examples?
Yes, we worked on 'Coupon Bazaar', which is a marketplace where people buy and sell coupons that provide a discount on products and services. Each coupon is represented as a digital asset that offers a special discount from the supplier.

We needed to develop several components of the application. First, we had to create a system for registering suppliers and managing coupons. Then, we required a verification feature and the ability for users to search for coupons.

During the course, we also added several new features, including a voting system and a functionality that allows for the verification and blacklisting of suppliers.
Initially, we studied the difference between smart assets, smart accounts, and dApp accounts, as well as the principles of working with verifier functions. Verifier functions allow altering the default behavior of an account. By default, they check transaction signatures, but the verifier function enables setting different 'rules'.
{-# STDLIB_VERSION 3 #-}
{-# CONTENT_TYPE DAPP #-}
{-# SCRIPT_TYPE ACCOUNT #-}
let ownerPublicKey = base58'H8ndsHjBha6oJBQQx33zqbP5wi8sQP7hwgjzWUv3q95M'
@Verifier(tx)
func verify() = {
match tx {
case SetScriptTransaction => sigVerify(tx.bodyBytes, tx.proofs[0], ownerPublicKey)
case DataTransaction => true
case _ => false
}
}Then we started adding coupons. We utilized one of the key features of dApp, allowing the recording of any type of data in the blockchain as key-value pairs – a data transaction. We combined it with a new transaction, invokeScript, which is used to call a function within the dApp from outside the blockchain.
The type of data transaction we used during the course was adding coupons to the marketplace:
let datajson = {
"title": "t-shirt with , vote 1",
"coupon_price": 10000000,
"old_price": 1000000000,
"new_price": 100000000,
"address": "Universe",
"description": "I want you to make love, not war, I know you've heard it before",
"image": "https://bit.ly/2EXTghg"
}
it('add item', async function(){
let ts = invokeScript({
dApp: dappAddress,
call:{
function: "addItem",
args:[
{ type: "string", value: datajson.title },
{ type: "integer", value: datajson.coupon_price },
{ type: "string", value: JSON.stringify(datajson) }
]},
payment: []
}, accountSupplierSeed)
let tx = await broadcast(ts)
await waitForTx(tx.id)
})To process this data with the addItem function and develop the purchasing function along with other options, we used a callable function that the user can invoke from outside the blockchain. As a result, it can perform various tasks, such as initiating fund transfers, writing or updating data in the dApp data storage, etc.
Here is an example of a callable function used in the addItem function:
@Callable(i)
func addItem(title: String, price: Int, data: String) = {
let supplierAddress = toBase58String(i.caller.bytes)
let item = getKeyItem(supplierAddress, title)
if (price <= 0) then throw("purchase amount cannot be less than item price")
elseif (getValueItemSupplier(item) != NONE) then throw("an item already exists")
else {
WriteSet([
DataEntry(getKeyItemSupplier(item), supplierAddress),
DataEntry(getKeyItemPrice(item), price),
DataEntry(getKeyItemData(item), data)
])
}
}Later, we developed a voting system that allows users to vote for promoting or removing certain products. To prevent external influence on the voting process, it uses the 'Commit-Reveal' scheme.
The 'commit' phase is used to collect encrypted votes using a hash function and 'salt'.
The 'reveal' phase is used to gather encrypted votes and compare their hashes.
Here is an example of a callable function used here:
@Callable(i)
func voteCommit(item: String, hash: String) = {
let user = toBase58String(i.caller.bytes)
let commits = getValueCommitsCount(item)
let status = getValueItemStatus(item)
if (commits >= VOTERS) then throw("reached max num of voters")
elseif (getValueCommit(item, user) != NONE) then throw("user has already participated")
elseif (getKeyItemSupplier(item) == NONE) then throw("item does not exist")
elseif (status != NONE && status != VOTING) then throw("voting is not possible")
else {
WriteSet([
DataEntry(getKeyCommit(item, user), hash),
DataEntry(getKeyCommitsCount(item), commits + 1),
DataEntry(getKeyItemStatus(item), if (commits == VOTERS) then REVEAL else VOTING)
])
}
}What else did you learn from the course?
The course also included tokenization and non-fungible tokens (NFTs) – tokens representing something unique and thus non-fungible.
The last session focused on oracles. Since the blockchain cannot receive data from the external world, we need oracles to send this data into it.
For our marketplace, oracles were needed to verify and, if necessary, blacklist a supplier who, for example, did not accept a sold coupon.
Here is an example:
func getExtValueItemWhiteListStatus(item: String) = {
item + "_verifier_status"
}
let verifier = "3Mx9qgMyMhHt7WUZr6PsaXNfmydxMG7YMxv"
let VERIFIED = "verified"
let BLACKLISTED = "blacklist"
@Callable(i)
func setstatus(supplier: String, status: String) = {
let account = toBase58String(i.caller.bytes)
if (account != verifier) then throw("only oracle verifier are able to manage whitelist")
elseif (status != VERIFIED && status != BLACKLISTED) then throw("wrong status")
else {
WriteSet([
DataEntry(getExtValueItemWhiteListStatus(supplier), status)
])
}
}
What was the most useful for you?
The most useful part was the assignments. Thanks to them, the lecture material became clearer, and the newly acquired knowledge was consolidated through trial and error. The practical work with , and .
How do you plan to apply what you learned in practice?
From the very beginning, I expected the course to help take my project to the next level. The idea was to now write the code in RIDE. The existing version already has document certification functions, but thanks to RIDE, it can be significantly improved. The new version will be more flexible and user-friendly, with more features, including certification of emails, agreements between multiple parties, etc.
The course also provided food for thought, and I came up with many new ideas. I am confident that the results will manifest in the future.
Source: habr.com
