# Signer
# Общие сведения
Signer — TypeScript/JavaScript-библиотека, которая позволяет вашему веб-приложению подписывать и отправлять транзакции от имени пользователей, не запрашивая у них секретную фразу (seed) или закрытый ключ.
Исходный код библиотеки доступен на Github: https://github.com/wavesplatform/signer.
# Провайдер
Для работы Signer необходимо подключить внешнюю библиотеку — Провайдер. Провайдер обеспечивает безопасное хранение приватных данных пользователя. Ни ваше приложение, ни Signer не имеют доступа к закрытому ключу и секретной фразе (seed) пользователя.
Провайдер выполняет аутентификацию пользователя и генерацию цифровой подписи.
Signer предоставляет приложению удобный протокол взаимодействия с Провайдером, а также отправляет транзакции в блокчейн.
В данный момент вы можете подключить один из следующих Провайдеров:
ProviderKeeper использует браузерное расширение Keeper Wallet.
ProviderCloud, разработанный командой WX.Network, использует аккаунт WX.Network на основе Email.
ProviderWeb, разработанный командой WX.Network, использует аккаунт, созданный или импортированный в веб-приложение WX.Network через секретную фразу или приватный ключ.
ProviderLedger использует устройство Ledger Nano X или Ledger Nano S.
ProviderMetaMask использует браузерное расширение MetaMask.
Пользователям MetaMask в сети Waves доступны только перевод токена и вызов скрипта. Подробнее см. в разделе Подписание транзакций и ордеров в MetaMask.
ProviderSeed создает аккаунт пользователя из секретной фразы. ProviderSeed можно использовать на этапе разработки и отладки приложения.
Вы также можете разработать собственный Провайдер, см. подраздел Интерфейс Провайдера.
# Signer + ProviderWeb: как это работает
Получив от Signer запрос на подписание транзакции, ProviderWeb открывает iframe, в котором пользователь может посмотреть детали транзакции, подтвердить или отклонить ее. Получив подтверждение от пользователя, ProviderWeb генерирует цифровую подпись. Процесс подписания транзакции продемонстрирован в следующем видео.
# Ограничения
Signer поддерживает все типы транзакций, кроме транзакций обмена и транзакций обновления информации ассета.
Signer поддерживает все браузеры, кроме Brave.
# Начало работы
# 1. Установка библиотек Signer и Провайдера
Чтобы установить Signer, используйте команду
npm i @waves/signer
Чтобы установить ProviderKeeper, используйте команду
npm i @waves/provider-keeper
Чтобы установить ProviderCloud от WX.Network, используйте команду
npm i @waves.exchange/provider-cloud
Для Windows используйте следующий формат:
npm i '@waves.exchange/provider-cloud'
Чтобы установить ProviderWeb от WX.Network, используйте команду
npm i @waves.exchange/provider-web
Для Windows используйте следующий формат:
npm i '@waves.exchange/provider-web'
Чтобы установить ProviderLedger, используйте команду
npm i @waves/provider-ledger
Чтобы установить ProviderMetamask, используйте команду
npm i @waves/provider-metamask
Чтобы установить ProviderSeed, используйте команду
npm i @waves/provider-seed @waves/waves-transactions
# 2. Подключение библиотек
Инициализируйте библиотеки в приложении.
Для работы с Testnet и ProviderKeeper:
import { Signer } from '@waves/signer'; import { ProviderKeeper } from '@waves/provider-keeper'; const signer = new Signer({ // Укажите адрес ноды, подключенной к Testnet NODE_URL: 'https://nodes-testnet.wavesnodes.com', }); const keeper = new ProviderKeeper(); signer.setProvider(keeper);
Для работы с Testnet и WX.Network ProviderCloud:
import { Signer } from '@waves/signer'; import { ProviderCloud } from '@waves.exchange/provider-cloud'; const signer = new Signer({ // Укажите адрес ноды, подключенной к Testnet NODE_URL: 'https://nodes-testnet.wavesnodes.com' }); signer.setProvider(new ProviderCloud())
Для работы с Testnet и WX.Network ProviderWeb:
import { Signer } from '@waves/signer'; import { ProviderWeb } from '@waves.exchange/provider-web'; const signer = new Signer({ // Укажите адрес ноды, подключенной к Testnet NODE_URL: 'https://nodes-testnet.wavesnodes.com' }); signer.setProvider(new ProviderWeb('https://testnet.waves.exchange/signer/'))
Для работы с Testnet и ProviderLedger:
import { Signer } from '@waves/signer'; import { ProviderLedger } from '@waves/provider-ledger'; const signer = new Signer({ // Specify URL of the node on Testnet NODE_URL: 'https://nodes-testnet.wavesnodes.com' }); signer.setProvider(new ProviderLedger({ // Specify chain ID of Testnet wavesLedgerConfig: { networkCode: 84, }, }));
Для работы с Testnet и ProviderMetamask:
import { Signer } from '@waves/signer'; import { ProviderMetamask } from '@waves/provider-metamask'; const signer = new Signer({ // Specify URL of the node on Testnet NODE_URL: 'https://nodes-testnet.wavesnodes.com' }); signer.setProvider(new ProviderMetamask()); }));
Для работы с Testnet и ProviderSeed:
import { Signer } from '@waves/signer'; import { ProviderSeed } from '@waves/provider-seed'; import { libs } from '@waves/waves-transactions'; const seed = libs.crypto.randomSeed(15); const signer = new Signer({ // Укажите адрес ноды, подключенной к Testnet NODE_URL: 'https://nodes-testnet.wavesnodes.com' }); signer.setProvider(new ProviderSeed(seed));
Для работы с Mainnet и ProviderKeeper:
import { Signer } from '@waves/signer'; import { ProviderKeeper } from '@waves/provider-keeper'; const signer = new Signer(); const keeper = new ProviderKeeper(); signer.setProvider(keeper);
Для работы с Mainnet и WX.Network ProviderCloud:
import { Signer } from '@waves/signer'; import { ProviderCloud } from '@waves.exchange/provider-cloud'; const signer = new Signer(); signer.setProvider(new ProviderCloud());
Для работы с Mainnet и WX.Network ProviderWeb:
import { Signer } from '@waves/signer'; import { ProviderWeb } from '@waves.exchange/provider-web'; const signer = new Signer(); signer.setProvider(new ProviderWeb());
Для работы с Mainnet и ProviderLedger:
import { Signer } from '@waves/signer'; import { ProviderLedger } from '@waves/provider-ledger'; const signer = new Signer(); const provider = new ProviderLedger(); signer.setProvider(provider);
Для работы с Mainnet и ProviderMetamask:
import { Signer } from '@waves/signer'; import { ProviderMetamask } from '@waves/provider-metamask'; const signer = new Signer(); const provider = new ProviderMetamask(); signer.setProvider(provider);
Теперь ваше приложение может использовать функции Signer.
# 3. Базовый пример
Ваше приложение готово к работе с блокчейном Waves. Попробуем использовать базовые функции: аутентифицировать пользователя, получить его баланс, перевести токены.
const user = await signer.login();
const balances = await signer.getBalance();
const [broadcastedTransfer] = await signer
.transfer({amount: 100000000, recipient: 'alias:T:merry'}) // Перевод 1 WAVES алиасу merry
.broadcast(); // Promise будет разрешен после подписания транзакции пользователем и получения ответа ноды
const [signedTransfer] = await signer
.transfer({amount: 100000000, recipient: 'alias:T:merry'}) // Перевод 1 WAVES алиасу merry
.sign(); // Promise будет разрешен после подписания транзакции пользователем
# Другие примеры
- Приложение, реализующее кнопку сбора пожертвований: https://github.com/vlzhr/crypto-donate.
- Приложение, реализующее отправку транзакций трех типов: https://github.com/vlzhr/waves-signer-example.
# Конструктор
new Signer({
NODE_URL: 'string',
})
Создает объект с перечисленными ниже методами.
Параметры:
Имя параметра | Значение по умолчанию | Описание |
---|---|---|
NODE_URL | https://nodes.wavesnodes.com | Нода, используемая для доступа к блокчейну |
# Методы
В коде можно использовать типы TypeScript.
# Данные пользователя
# login
Выполняет вход в аккаунт пользователя; если у пользователя еще нет аккаунта — создает его.
login();
Возвращает: Promise пользовательских данных: адреса и открытого ключа.
При использовании ProviderMetamask возвращается пустой открытый ключ.
Пример вызова:
const {address, publicKey} = await signer.login();
Пример результата:
{
address: '3P8pGyzZL9AUuFs9YRYPDV3vm73T48ptZxs',
publicKey: 'FuChbN7t3gvW5esgARFytKNVuHSCZpXSYf1y3eDSruEN',
}
# logout
Выполняет выход из аккаунта.
logout();
Возвращает: Promise<void>.
Пример вызова:
await signer.logout();
# getBalance
Если пользователь вошел в аккаунт, функция получает текущий баланс всех ассетов в портфеле пользователя.
getBalance();
Возвращает: Promise списка ассетов и их балансов.
Пример вызова:
const balances = await signer.getBalance();
Пример результата:
[{
assetId: 'WAVES',
assetName: 'Waves',
decimals: 8,
amount: 100000000,
isMyAsset: false,
tokens: 1,
sponsorship: null,
isSmart: false
},
{
assetId: 'AcrRM9STdBu5PNiFveTCbRFTS8tADhKcsbC2KBp8A4tx',
assetName: 'CoffeeCoin',
decimals: 3,
amount: 1500,
isMyAsset: false,
tokens: 1.5,
isSmart: false,
sponsorship: 500
}]
Поля результата:
Имя поля | Описание |
---|---|
assetId | Идентификатор ассета в кодировке Base58 |
assetName | Название ассета |
decimals | Количество знаков после запятой в балансе ассета |
amount | Баланс ассета, умноженный на 10decimals . Например, для WAVES decimals равно 8, поэтому фактическое количество WAVES умножается на 108. { "WAVES": 677728840 } означает 6,77728840 WAVES |
isMyAsset | true , если ассет выпущен текущим пользователем |
tokens | Баланс ассета для отображения в приложении |
sponsorship | Количество спонсорского ассета, взимаемое с пользователей (эквивалент 0,001 WAVES), умноженное на 10decimals null — если токен не является спосорским |
isSmart | true для смарт-ассетов |
# getSponsoredBalances
Если пользователь вошел в аккаунт, функция получает текущий баланс спонсорских ассетов в портфеле пользователя. См. раздел Спонсирование.
getSponsoredBalances();
Возвращает: Promise списка ассетов и их балансов.
Пример вызова:
const sponsoredBalances = await signer.getSponsoredBalances();
Пример результата:
[{
assetId: 'AcrRM9STdBu5PNiFveTCbRFTS8tADhKcsbC2KBp8A4tx',
assetName: 'CoffeeCoin',
decimals: 3,
amount: 1500,
isMyAsset: false,
tokens: 1.5,
isSmart: false,
sponsorship: 500
}]
Поля результата такие же, как у метода getBalance.
# Создание транзакций
Следующие методы создают транзакции (но не подписывают их и не отправляют в блокчейн):
- alias
- burn
- cancelLease
- data
- invoke
- issue
- lease
- massTransfer
- reissue
- setAssetScript
- setScript
- sponsorship
- transfer
Проверьте, какие типы транзакций поддерживает используемый вами Провайдер.
# Общие параметры
Каждый из методов создания транзакции имеет необязательные параметры, которые в большинстве случаев не требуется указывать в явном виде:
Имя поля | Описание | Значение по умолчанию |
---|---|---|
chainId | 'W'.charCodeAt(0) или 87 — Mainnet 'T'.charCodeAt(0) или 84 — Testnet 'S'.charCodeAt(0) или 83 — Stagenet | Определяется конфигурацией ноды Waves, указанной в Конструкторе |
fee | Комиссия за транзакцию | Минимальная комиссия за транзакцию, см. раздел Комиссия за транзакцию. ⚠️ Внимание! При расчете значения по умолчанию для транзакции вызова скрипта не учитываются действия скрипта. Подробнее в разделе invoke ниже |
proofs | Массив подтверждений транзакции | Добавляется методом sign или broadcast (см. подраздел Как подписать и отправить транзакцию). Если вы указываете подтверждение вручную, оно также добваляется в массив |
senderPublicKey | Открытый ключ отправителя транзакции в кодировке Base58 | Возвращается методом login |
# Как подписать и отправить транзакцию
Каждый из методов создания транзакции возвращает объект, у которого есть методы sign
и broadcast
.
Чтобы подписать транзакцию, используйте метод sign
. Пример:
signer.invoke({
dApp: address,
call: { function: name, args: convertedArgs },
}).sign();
Чтобы подписать транзакцию и сразу отправить ее в блокчейн, используйте метод broadcast
. Пример:
signer.invoke({
dApp: address,
call: { function: name, args: convertedArgs },
}).broadcast();
В методе
broadcast
можно использовать те же опции, что и в методе signer.broadcast, описание которого приведено ниже.
Вы можете подписать или отправить сразу несколько транзакций. Пример:
signer.alias({ 'new_alias', })
.data([{ key: 'value', type: 'integer', value: 1 ])
.transfer({ recipient: '3P8pGyzZL9AUuFs9YRYPDV3vm73T48ptZxs', amount: 10000 })
}).broadcast();
# alias
Создает транзакцию создания псевдонима.
alias(data: {
alias: 'string'
})
Параметры:
Имя параметра | Значение по умолчанию | Описание |
---|---|---|
alias* | Короткое, удобное для запоминания имя адреса. См. Псевдоним |
* Обязательный параметр.
См. Общие параметры для описания остальных параметров.
Пример вызова:
const data = {
alias: 'new_alias',
}
const [tx] = await signer
.alias(data)
.broadcast();
# burn
Создает транзакцию сжигания токена.
burn(data: {
assetId*: 'string',
quantity*: LONG,
})
Параметры:
Имя параметра | Значение по умолчанию | Описание |
---|---|---|
assetId* | Идентификатор сжигаемого ассета в кодировке Base58 | |
quantity* | Количество сжигаемого ассета, умноженное на 10decimals. Например, для WAVES decimals равно 8, поэтому фактическое количество WAVES умножается на 108. { "WAVES": 677728840 } означает 6,77728840 WAVES |
* Обязательный параметр.
См. Общие параметры для описания остальных параметров.
Пример вызова:
const data = {
assetId: '4uK8i4ThRGbehENwa6MxyLtxAjAo1Rj9fduborGExarC',
quantity: 100,
}
const [tx] = await signer
.burn(data)
.broadcast();
# cancelLease
Создает транзакцию закрытия лизинга.
cancelLease(data: {
leaseId: 'string',
})
Параметры:
Имя параметра | Значение по умолчанию | Описание |
---|---|---|
leasetId* | Идентификатор транзакции лизинга в кодировка Base58 |
* Обязательный параметр.
См. Общие параметры для описания остальных параметров.
Пример вызова:
const data = {
leaseId: '69HK14PEHq2UGRfRYghVW8Kc3487uJaoUmk2ntT4kw7X',
}
const [tx] = await signer
.cancelLease(data)
.broadcast();
# data
Создает транзакцию данных.
data(data: [{
key: 'string',
type: 'string' | 'integer' | 'binary' | 'boolean',
value: 'string' | number | boolean,
])
Параметры:
Имя параметра | Значение по умолчанию | Описание |
---|---|---|
key* | Ключ записи. Не более 100 символов | |
type | Тип записи | |
value* | Значение записи. Не более 5 Кбайт |
* Обязательный параметр.
См. Общие параметры для описания остальных параметров.
Пример вызова:
const records = [
{ key: 'name', type: 'string', value: 'Lorem ipsum dolor sit amet' },
{ key: 'value', type: 'integer', value: 1234567 },
{ key: 'flag', type: 'boolean', value: true }
]
const [tx] = await signer
.data({ data: records })
.broadcast();
# invoke
Создает транзакцию вызова скрипта.
invoke(data: {
dApp: 'string',
fee: LONG,
payment: [{
assetId: 'string',
amount: LONG,
}],
call: {
function: 'string',
args: [{
type: 'integer' | 'string' | 'binary',
value: number | 'string',
}],
},
feeAssetId: 'string',
})
Параметры:
Имя параметра | Значение по умолчанию | Описание |
---|---|---|
dApp* | Адрес в кодировке Base58 или псевдоним (с префиксом alias:T: ) dApp-скрипта, который нужно вызвать | |
fee | ⚠️ Внимание! Значение по умолчанию не учитывает действия скрипта. В случае вызова функции dApp-скрипта, которая выполняет выпуск токенов, не являющихся NFT, рассчитайте комиссию самостоятельно, в соответствии с описанием в разделе Транзакция вызова скрипта | |
payment | Платежи, приложенные к вызову. Не более 10 платежей | |
payment.assetId* | Идентификатор ассета платежа в кодировке Base58. WAVES или null соответствуют WAVES | |
payment.amount* | Количество ассета, умноженное на 10decimals . Например, для WAVES decimals равно 8, поэтому фактическое количество WAVES умножается на 108. { "WAVES": 677728840 } означает 6,77728840 WAVES | |
call | Вызывается функция по умолчанию | Параметры вызываемой функции |
call.function* | Имя вызываемой функции | |
call.args* | Аргументы вызываемой функции | |
call.args.type* | Тип аргумента | |
call.args.value* | Значение аргумента | |
feeAssetId | WAVES | Идентификатор спонсорского ассета, в котором будет уплачена комиссия за транзакцию, в кодировке Base58. См. раздел Спонсирование. null или отсутствующий параметр означает WAVES |
* Обязательный параметр.
См. Общие параметры для описания остальных параметров.
Пример вызова:
const data = {
dApp: '3Fb641A9hWy63K18KsBJwns64McmdEATgJd',
fee: 1000000,
payment: [{
assetId: '73pu8pHFNpj9tmWuYjqnZ962tXzJvLGX86dxjZxGYhoK',
amount: 7,
}],
call: {
function: 'foo',
args: [
{ type: 'integer', value: 1 },
{ type: 'binary', value: 'base64:AAA=' },
{ type: 'string', value: 'foo' }
],
},
}
const [tx] = await signer
.invoke(data)
.broadcast();
# issue
Создает транзакцию выпуска.
issue(data: {
name: 'string',
decimals: number,
quantity: LONG,
reissuable: boolean,
description: 'string',
script: 'string',
})
Параметры:
Имя параметра | Значение по умолчанию | Описание |
---|---|---|
name* | Название ассета | |
decimals* | Количество знаков после запятой | |
quantity* | Количество ассета, умноженное на 10decimals | |
reissuable* | true – довыпуск возможен;false — довыпуск невозможен | |
description* | Описание ассета | |
script | Скрипт ассета в кодировке Base64 (с префиксом base64: ) |
* Обязательный параметр.
См. Общие параметры для описания остальных параметров.
Пример вызова:
const data = {
name: 'MyToken',
decimals: 8,
quantity: 100000000000,
reissuable: true,
description: 'It is a gaming token',
}
const [tx] = await signer
.issue(data)
.broadcast();
# lease
Создает транзакцию лизинга.
lease(data: {
amount: LONG,
recipient: 'string',
})
Параметры:
Имя параметра | Значение по умолчанию | Описание |
---|---|---|
amount* | Количество WAVES, умноженное на 10decimals . { "WAVES": 677728840 } означает 6,77728840 WAVES | |
recipient* | Адрес получателя в кодировке Base58 или алиас получателя (с префиксом alias:T: ) |
* Обязательный параметр.
См. Общие параметры для описания остальных параметров.
Пример вызова:
const data = {
amount: 10000,
recipient: 'alias:T:merry',
}
const [tx] = await signer
.lease(data)
.broadcast();
# massTransfer
Создает транзакцию массового перевода.
massTransfer(data: {
assetId: 'string',
transfers: [{
amount: LONG,
recipient: 'string',
}],
attachment: 'string',
})
Параметры:
Имя параметра | Значение по умолчанию | Описание |
---|---|---|
assetId | WAVES | Идентификатор ассета в кодировке Base58 |
transfers* | Список переводов | |
transfers.amount* | Количество ассета, умноженное на 10decimals . Например, для WAVES decimals равно 8, поэтому фактическое количество WAVES умножается на 108. { "WAVES": 677728840 } означает 6,77728840 WAVES | |
transfers.recipient* | Адрес получателя в фодировке Base58 или алиас получателя (с префиксом alias:T: ) | |
attachment | Произвольные данные: байты в кодировке Base58. Обычно используются для комментария к переводу. Не более 140 байт |
* Обязательный параметр.
См. Общие параметры для описания остальных параметров.
Пример вызова:
const crypto = require('@waves/ts-lib-crypto')
const data = {
transfers: [
{
amount: 100,
recipient: '3P23fi1qfVw6RVDn4CH2a5nNouEtWNQ4THs',
},
{
amount: 200,
recipient: 'alias:T:merry',
}],
attachment: crypto.base58Encode(crypto.stringToBytes('sample message for recipient'))
]
const [tx] = await signer
.massTransfer(data)
.broadcast();
# reissue
Создает транзакцию довыпуска.
reissue(data: {
assetId: 'string',
quantity: LONG,
reissuable: boolean,
})
Параметры:
Имя параметра | Значение по умолчанию | Описание |
---|---|---|
assetId* | Идентификатор ассета в кодировке Base58 | |
quantity* | Количество ассета к довыпуску, умноженное на 10decimals | |
reissuable* | true – повторный довыпуск возможен.false — повторный довыпуск невозможен |
* Обязательный параметр.
См. Общие параметры для описания остальных параметров.
Пример вызова:
const data = {
assetId: 'AcrRM9STdBu5PNiFveTCbRFTS8tADhKcsbC2KBp8A4tx'
quantity: 100000000000,
reissuable: true,
}
const [tx] = await signer
.reissue(data)
.broadcast();
# setAssetScript
Создает транзакцию установки скрипта ассета.
setAssetScript(data: {
assetId: 'string',
script: 'string',
})
Параметры:
Имя параметра | Значение по умолчанию | Описание |
---|---|---|
assetId* | Идентификатор ассета в кодировке Base58 | |
script | Скрипт ассета в кодировке Base64 (с префиксом base64: ) |
* Обязательный параметр.
См. Общие параметры для описания остальных параметров.
Пример вызова:
const data = {
assetId: 'AcrRM9STdBu5PNiFveTCbRFTS8tADhKcsbC2KBp8A4tx',
script: 'base64:AwZd0cYf...',
}
const [tx] = await signer
.setAssetScript(data)
.broadcast();
# setScript
Создает транзакцию установки скрипта.
setScript(data: {
script: 'string',
})
Параметры:
Имя параметра | Значение по умолчанию | Описание |
---|---|---|
script | Скрипт аккаунта или dApp-скрипт в кодировке Base64 (с префиксом base64: ). null — отмена установки скрипта |
См. Общие параметры для описания остальных параметров.
Пример вызова:
const data = {
script: 'base64:AAIDAAAAAAAAAAQIARIAAAAAAAAAAA...',
}
const [tx] = await signer
.setScript(data)
.broadcast();
# sponsorship
Создает транзакцию спонсирования.
sponsorship(data: {
assetId: 'string',
minSponsoredAssetFee: LONG,
})
Параметры:
Имя параметра | Значение по умолчанию | Описание |
---|---|---|
assetId* | Идентификатор ассета в кодировке Base58 | |
minSponsoredAssetFee | Количество спонсорского ассета, взимаемое с пользователей (эквивалент 0,001 WAVES), умноженное на 10decimals |
* Обязательный параметр.
См. Общие параметры для описания остальных параметров.
Пример вызова:
const data = {
assetId: 'AcrRM9STdBu5PNiFveTCbRFTS8tADhKcsbC2KBp8A4tx',
minSponsoredAssetFee: 314,
}
const [tx] = await signer
.sponsorship(data)
.broadcast();
# transfer
Создает транзакцию перевода.
transfer(data: {
recipient: 'string',
amount: LONG,
assetId: 'string',
attachment: 'string',
feeAssetId: 'string',
})
Параметры:
Имя параметра | Значение по умолчанию | Описание |
---|---|---|
recipient* | Адрес получателя в кодировке Base58 или алиас получателя (с префиксом alias:T: ) | |
amount* | Количество ассета, умноженное на 10decimals . Например, для WAVES decimals равно 8, поэтому фактическое количество WAVES умножается на 108. { "WAVES": 677728840 } означает 6,77728840 WAVES | |
assetId | WAVES | Идентификатор ассета в кодировке Base58. null или отсутствующий параметр означает WAVES |
attachment | Произвольные данные: байты в кодировке Base58. Обычно используются для комментария к переводу. Не более 140 байт | |
feeAssetId | WAVES | Идентификатор спонсорского ассета, в котором будет уплачена комиссия за транзакцию, в кодировке Base58. См. раздел Спонсирование. null или отсутствующий параметр означает WAVES |
* Обязательный параметр.
См. Общие параметры для описания остальных параметров.
Пример вызова:
const crypto = require('@waves/ts-lib-crypto')
const data = {
recipient: '3P8pGyzZL9AUuFs9YRYPDV3vm73T48ptZxs',
amount: 10000,
attachment: crypto.base58Encode(crypto.stringToBytes('sample message for recipient'))
}
const [tx] = await signer
.transfer(data)
.broadcast();
# batch
Создает список транзакций.
batch([{
type: number,
... // поля, зависящие от типа транзакции
}])
Параметры:
Имя параметра | Значение по умолчанию | Описание |
---|---|---|
type* | Идентификатор типа транзакции |
* Обязательный параметр.
Пример вызова:
const [transfer, alias, issue] = await signer.batch([
{
type: 4,
recipient: 'alias:T:merry',
amount: 100000000
},
{
type: 10,
alias: 'send33'
},
{
type: 3,
name: 'SomeTokenName',
description: 'Some Token Description',
reissuable: false,
quantity: 100,
decimals: 1
}
]).sign(); // Или broadcast
В этом примере метод sign
возвращает массив подписанных транзакций, в том же порядке, в котором они были приведены в batch
.
# Прочие методы
# broadcast
Оправляет ранее подписанные транзакции в блокчейн.
broadcast(tx,[options])
Возвращает: Promise ответа ноды. См. описание метода POST /transactions/broadcast Node API.
Параметры:
Имя параметра | Значение по умолчанию | Описание |
---|---|---|
tx* | Подписанная транзакция или массив подписанных транзакций | |
options.chain | false | [Тип: boolean] Отправлять следующую транзакцию только после того, как в блокчейн добавлен блок с предыдущей транзакцией и затем еще количество блоков, указанное в параметре options.confirmations |
options.confirmations | -1 | Уровень подтверждения, при котором будет разрешен Promise: меньше 0 – Promise разрешается, когда транзакция попадает в UTX pool 0 – Promise разрешается, когда блок, содержащий транзакцию, попадает в блокчейн 1 – Promise разрешается, когда в блокчейн добавляется еще один блок и т. д. |
* Обязательный параметр.
Пример вызова:
const [transfer1] = await signer.transfer({amount: 1, recipient: 'alias:T:merry'}).sign();
const [transfer2] = await signer.transfer({amount: 1, recipient: 'alias:T:merry'}).sign();
await signer.broadcast([transfer1, transfer2], {chain: true, confirmations: 2});
В этом примере последовательность событий следующая:
- Транзакция
transfer1
передается на ноду и помещается в UTX pool. - Блок с транзакцией
transfer1
и еще два блока добавляются в блокчейн. - Транзакция
transfer2
передается на ноду и помещается в UTX pool. - Блок с транзакцией
transfer2
и еще два блока добавляются в блокчейн. - Происходит разрешение Promise, и вы можете сообщить пользователю, что его транзакции подтверждены.
# getNetworkByte
Получает байт сети.
getNetworkByte();
Возвращает: Promise байта сети.
Пример вызова:
const chainId = signer.getNetworkByte();
# setProvider
Устанавливает Провайдера, который используется для подписания транзакций. Требования к Провайдеру приведены в разделе Интерфейс Провайдера.
setProvider(provider);
Параметры:
Имя параметра | Значение по умолчанию | Описание |
---|---|---|
provider* | Объект, который реализует интерфейс провайдера |
* Обязательный параметр.
Пример вызова:
signer.setProvider(new Provider());
# signMessage
Получает цифровую подпись пользователя для заданного сообщения. Проверка подписи позволяет убедиться, что аккаунт Waves принадлежит именно этому пользователю.
signMessage(data: string | number)
Параметры:
Имя параметра | Значение по умолчанию | Описание |
---|---|---|
data* | Подписываемые данные: строка или число. Если указано число, оно вначале преобразуется в строку |
* Обязательный параметр.
Пример вызова:
const signature = await signer.signMessage('Ride the Waves!')
Проверка подписи
Все провайдеры, кроме ProviderMetamask
Провайдеры добавляют префикс [255, 255, 255, 1] к подписываемым байтам. Это сделано для того, чтобы в этом методе было невозможно подписать данные транзакций, что может привести к фишингу.
Пример проверки подписи:
const crypto = require('@waves/ts-lib-crypto');
const userData = await signer.login();
const signature = await signer.signMessage('Ride the Waves!')
crypto.verifySignature(userData.publicKey, [255, 255, 255, 1, ...crypto.stringToBytes('Ride the Waves!')], signature))
ProviderMetamask
ProviderMetamask использует спецификацию EIP-712 и версию 4 функции signTypedData
API MetaMask. На подпись передается следующая структура:
[
{
"types": {
"EIP712Domain": [
{
"name": "chainId",
"type" :"uint256"
},
],
"Message": [
{
"name": "text",
"type": "string"
}
]
},
"domain": {
"chainId": <87|84|83>
},
"primaryType": "Message",
"message": {
"text": "<some custom message>"
}
}
]
Чтобы проверить подпись, нужно восстановить адрес пользователя из подписи и подписанных данных с помощью версии 4 функции recoverTypedSignature
и сравнить с ожидаемым.
Пример проверки подписи:
const { recoverTypedSignature } = require('@metamask/eth-sig-util');
const { wavesAddress2eth } = require('@waves/node-api-js');
const userData = await signer.login();
const signature = await signer.signMessage('Ride the Waves!')
const msg = {
"types": {
"EIP712Domain": [
{
"name": "chainId",
"type" :"uint256"
},
],
"Message": [
{
"name": "text",
"type": "string"
}
]
},
"domain": {
"chainId": 'T'.charCodeAt(0) // 'W'.charCodeAt(0) for Mainnet
},
"primaryType": "Message",
"message": {
"text": "Ride the Waves!"
}
};
const recovered = recoverTypedSignature({
data: msg,
signature: signature,
version: 'V4'
});
recovered === wavesAddress2eth(userData.address)
# waitTxConfirm
Ожидает появления транзакции в блокчейне.
waitTxConfirm(tx, confirmations)
Параметры:
Имя параметра | Значение по умолчанию | Описание |
---|---|---|
tx* | Транзакция или массив транзакций, отправленных в блокчейн | |
confirmations* | Количество блоков, добавленных в блокчейн после блока, содержащего транзакцию |
* Обязательный параметр.
Пример вызова:
const [tx] = await signer
.transfer({amount: 10000000, recipient: 'alias:T:merry'})
.broadcast();
signer.waitTxConfirm(tx, 1).then((tx) => {
// Требуется еще один блок в блокчейне
}});
# Интерфейс Провайдера
⚠️ Чтобы обеспечить конфиденциальность данных пользователя, Провайдер следует реализовывать на основе
iframe
.
Провайдер должен предоставлять следующий интерфейс:
interface Provider {
/**
* Signer подписывается на события login в Провайдере
* При срабатывании Провайдер должен передать данные пользователя: адрес и публичный ключ
* Для последующей отписки Signer вызывает функцию off
*/
on(
event: 'login',
handler:({ address: string; publicKey: string }) => any
) => Provider;
/**
* Signer подписывается на события logout в Провайдере
* Для последующей отписки Signer вызывает функцию off
*/
on( event: 'logout', handler:() => any) => Provider;
/**
* Signer подписывается на первое событие login в Провайдере
* При срабатывании Провайдер должен передать данные пользователя:
* адрес и публичный ключ, а также выполнить отписку
* Отписка не нужна
*/
once(
event: 'login',
handler:({ address: string; publicKey: string }) => any
) => Provider;
/**
* Signer подписывается на первое событие logout в Провайдере
* При срабатывании Провайдер должен выполнить отписку
*/
once( event: 'logout', handler:() => any) => Provider;
/**
* Signer отписывается от событий в Провайдере, на которые были подписки
*/
off(
event: 'login',
handler:({ address: string; publicKey: string }) => any
) => Provider;
off( event: 'logout', handler:() => any) => Provider;
/**
* Устанавливает соединение с нодой Waves
* @param options
*/
connect(options: {NODE_URL: string, NETWORK_BYTE: number}): Promise<void>;
/**
* Выполняет вход в аккаунт пользователя
*/
login(): Promise<{address: string, publicKey: string}>;
/**
* Выполняет выход из аккаунта пользователя
*/
logout(): Promise<void>;
/**
* Подписывает произвольную строку
* @param data
*/
signMessage(data: string | number): Promise<string>;
/**
* Подписывает типизированные данные
* @param data
*/
signTypedData(data: Array<TypedData>): Promise<string>;
/**
* Подписывает транзакции в массиве
* Здесь SignedTx<T> — любая транзакция, T[] — массив любых транзакций
* @param list
*/
sign<T extends SignerTx>(toSign: T[]): Promise<SignedTx<T>>;
sign<T extends Array<SignerTx>>(toSign: T): Promise<SignedTx<T>>;
}
# Коды ошибок
Класс ошибки | Код | Тип | Описание |
---|---|---|---|
SignerOptionsError | 1000 | validation | Invalid signer options: NODE_URL, debug |
SignerNetworkByteError | 1001 | network | Could not fetch network from {NODE_URL}: Failed to fetch |
SignerAuthError | 1002 | authorization | Can't use method: getBalance. User must be logged in |
SignerProviderConnectError | 1003 | network | Could not connect the Provider |
SignerEnsureProviderError | 1004 | provider | Can't use method: login. Provider instance is missing 🛈 Возможные причины: пользователь в режиме Инкогнито или отключил cookie |
SignerProviderInterfaceError | 1005 | validation | Invalid provider properties: connect |
SignerProviderInternalError | 1006 | provider | Provider internal error: {...}. This is not error of signer. |
SignerApiArgumentsError | 1007 | validation | Validation error for invoke transaction: {...}. Invalid arguments: senderPublicKey |
SignerNetworkError | 1008 | network | Network Error |