# Как создать и запустить dApp: полное пошаговое руководство
В этом разделе вы узнаете, как создать и запустить децентрализованное приложение, работающее на блокчейне.
Для создания и тестирования dApp мы используем Waves IDE. Для создания веб-приложения, которое вызывает функции dApp, мы используем JavaScript.
Процесс разработки dApp состоит из пяти простых шагов. Мы пройдем их один за другим. В результате должно получиться простое приложение Waves Magic 8 Ball — генератор превдослучайных ответов. В дальнейшем, повторяя эти шаги, вы сможете создать приложение любой сложности.
О возможностях dApp читайте в разделе Что такое dApp.
# План действий
- Создание аккаунта dApp.
- Написание dApp-скрипта.
- Установка скрипта на аккаунт dApp.
- Тестирование скрипта.
- Выход в реальный мир.
# Шаг 1. Создание аккаунта dApp
Откройте Waves IDE.
Нажмите и убедитесь, что вы работаете с Testnet.
Нажмите Add account → Generate new account.
Нажмите Show seed and private key и сохраните секретную фразу в укромном месте — она потребуется для восстановления доступа к аккаунту.
Пополните баланс аккаунта: в Testnet это бесплатно. Для этого:
• Скопируйте адрес аккаунта: нажмите на название аккаунта, затем нажмите кнопку .
• В Кране Waves вставьте адрес и нажмите Запросить WAVES.
# Шаг 2. Написание dApp-скрипта
- Нажмите кнопку и выберите dApp script.
- Замените автоматически сгенерированный код на текст вашего скрипта.
Файл скрипта сохраняется в Waves IDE автоматически.
Код скрипта Waves Magic 8 Ball можно скопировать из библиотеки: Library → ride4dapps → 8ball → ride → 8ball.ride.
Код скрипта
{-# STDLIB_VERSION 8 #-}
{-# CONTENT_TYPE DAPP #-}
{-# SCRIPT_TYPE ACCOUNT #-}
# Определяем количество и список ответов
let answersCount = 20
let answers =
["It is certain.",
"It is decidedly so.",
"Without a doubt.",
"Yes - definitely.",
"You may rely on it.",
"As I see it, yes.",
"Most likely.",
"Outlook good.",
"Yes.",
"Signs point to yes.",
"Reply hazy, try again.",
"Ask again later.",
"Better not tell you now.",
"Cannot predict now.",
"Concentrate and ask again.",
"Don't count on it.",
"My reply is no.",
"My sources say no.",
"Outlook not so good.",
"Very doubtful."]
# Функция-генератор псевдослучайных ответов
func getAnswer(question: String, previousAnswer: String) = {
let hash = sha256(toBytes(question + previousAnswer))
let index = toInt(hash)
answers[index % answersCount]
}
# Функция получения предыдущего ответа из хранилища
func getPreviousAnswer(address: String) = {
match getString(this, address + "_a") {
case a: String => a
case _ => address
}
}
# Функция ответа
@Callable(i)
func tellme(question: String) = {
# Получаем адрес пользователя, который вызывает контракт
let callerAddress = i.caller.toString()
# Получаем псевдослучайный ответ
let answer = getAnswer(question, getPreviousAnswer(callerAddress))
# Записываем данные в хранилище
[
StringEntry(callerAddress + "_q", question),
StringEntry(callerAddress + "_a", answer)
]
}
Пояснения к коду
dApp-скрипт должен начинаться с директив:
{-# STDLIB_VERSION 8 #-}
{-# CONTENT_TYPE DAPP #-}
{-# SCRIPT_TYPE ACCOUNT #-}
Между директивами и вызываемой функцией можно объявить переменные и вспомогательные функции.
Перед объявлением вызываемой функции нужно указать аннотацию @Callable(i)
. Объект i
содержит поля транзакции вызова скрипта, которые может использовать вызываемая функция. В нашем примере используется поле i.caller
— адрес аккаунта, вызвавшего функцию.
Результат вызываемой функции — набор действий скрипта. В нашем примере функция выполняет два действия StringEntry
, которые добавляют или изменяют запись строкового типа в хранилище данных dApp.
Подробнее о структуре dApp-скрипта читайте в разделе Структура dApp-скрипта.
# Шаг 3. Установка скрипта
Для установки dApp-скрипта на аккаунт нужно отправить с этого аккаунта транзакцию установки скрипта. Комиссия за установку скрипта составляет 0,01 WAVES.
Отправить транзакцию можно прямо из Waves IDE:
- Откройте dApp-скрипт и нажмите Deploy.
- Нажмите Add sign, чтобы добавить подпись к транзакции. Нажмите Publish.
Вы можете проверить установленный dApp-скрипт в Waves Explorer:
- Откройте https://wavesexplorer.com/ru.
- В правом верхнем углу переключитесь на Testnet.
- Выполните поиск по адресу аккаунта dApp.
- Перейдите на вкладку Скрипт.
dApp готов к использованию — его функции можно вызывать с помощью транзакции вызова скрипта.
# Шаг 4. Тестирование скрипта
Для тестирования dApp-скрипта нужно отправить транзакцию вызова скрипта. Комиссия за вызов скрипта составляет от 0,005 WAVES и зависит от количества смарт-ассетов, используемых в вызове (в нашем примере они не используются). Формула расчета комиссии приведена в разделе Комиссия за транзакцию.
Для ручного тестирования удобно использовать Waves Dapp Ui:
Создайте аккаунт тестового пользователя в рекомендуемом приложении-кошельке, например:
• или в расширении для браузера Keeper Wallet, переключив сеть на Testnet перед созданием аккаунта.
Пополните баланс аккаунта с помощью Крана Waves.
В Waves Dapp Ui вставьте адрес dApp.
Нажмите Sign In и подключите кошелек тестового пользователя.
Задайте параметры вызываемой функции и приложите платежи, если требуется.
Выполнить тесты можно прямо из Waves IDE. В тестах поддерживаются функции:
Создайте аккаунт тестового пользователя и пополните баланс — для этого повторите шаг 1.
Нажмите кнопку и выберите Test.
Замените автоматически сгенерированный код на ваш тест.
Код теста для скрипта Waves Magic 8 Ball можно скопировать из библиотеки: Library → ride4dapps → 8ball → tests → 8ball_test.js. Не забудьте заменить значение
ballAddress
на адрес своего dApp.Нажмите кнопку Run full test.
Код теста
describe('8 ball', () => {
const ballAddress = "3MxBZbnN8Z8sbYjjL5N3oG5C8nWq9NMeCEm"
const question = "Test" + Date.now()
const tx = invokeScript({fee: 500000, dApp: ballAddress, call:{function:"tellme", args:[{"type": "string", "value": question}]}, payment: null})
it('Tx is mined in block', async function(){
await broadcast(tx)
await waitForTx(tx.id)
})
it('Question is in ball', async function(){
await accountDataByKey(address()+"_q", ballAddress)
.then(reslove => expect(reslove.value).to.equal(question))
})
})
Вы можете проверить результат выполнения dApp-скрипта в Waves Explorer:
- Откройте https://wavesexplorer.com/ru.
- В меню справа вверху переключитесь на Testnet.
- Выполните поиск по адресу аккаунта dApp.
- Перейдите на вкладку Данные.
# Шаг 5. Выход в реальный мир
Для выхода в реальный мир:
- Создайте веб-приложение, в котором пользователь сможет, нажав кнопку, подписать и отправить транзакцию вызова скрипта.
- Добавьте ваш dApp на Mainnet.
- Зарегистрируйте приложение в каталогах dApp, чтобы как можно больше пользователей узнали о нем!
# 5.1. Создание веб-приложения
Чтобы вызывать функции dApp от имени реального пользователя, подключите TypeScript/JavaScript-библиотеку Signer. Signer позволяет вашему веб-приложению подписать и отправить транзакцию вызова скрипта, не запрашивая у пользователя его секретную фразу (seed) или закрытый ключ.
Код вызова скрипта
await signer.invoke({
dApp: ballAddress,
call: {
function: "tellme",
args:[{"type": "string", "value": question}]
}
}).broadcast();
Полный код приложения на Github
# 5.2. Добавление dApp на Mainnet
- В Waves IDE нажмите и переключитесь на Mainnet.
- Создайте аккаунт dApp на Mainnet — аналогично шагу 1.
- Пополните баланс аккаунта, чтобы оплатить комиссию за установку скрипта. См. раздел Как получить WAVES.
- Установите dApp-скрипт на аккаунт — аналогично шагу 3.
dApp на Mainnet получит другой адрес — не забудьте поменять его в веб-приложении. Кроме того, адрес ноды для отправки транзакции вызова скрипта нужно заменить на https://nodes.wavesnodes.com
.
💡 Если вы хотите сделать приложение бесплатным для пользователей и оплачивать вместо них комиссию за вызов скрипта, включите спонсирование.
# 5.3. Регистрация на DappRadar
DappRadar — крупнейший портал с рейтингом децентрализованных приложений. Добавьте в каталог dApp свое приложение, чтобы как можно больше пользователей узнали о нем.
# Что дальше
API публичных нод WAVES имеет ограничения на количество запросов в секунду. Поэтому, когда ваше приложение наберет популярность, рекомендуем запустить собственную ноду и отправлять транзакции вызова скрипта на нее.