В нашем Введение в CosmWasm JS мы говорили о концепции библиотеки, но еще не видели никакого кода. В Добавление CosmWasm в мультичейн кошелек Neuma мы использовали любую раннюю версию CosmWasmClient под капотом. Сегодня мы расскажем обо всем, что вам нужно знать об этом занятии.

Настройка REPL

Все, что мы здесь делаем, можно выполнить из любого скрипта Node.js, веб-приложения или расширения браузера. Но для демонстрации мы будем использовать REPL (цикл чтения – оценки – печати) в качестве игровой площадки. Вы можете установить REPL в свою локальную среду, но самый быстрый способ запустить REPL:

npx @cosmwasm/cli

который встретит вас таким экраном:

Это REPL, который работает очень похоже на то, что вы получаете, просто набирая node. Основными отличиями являются встроенная поддержка TypeScript и ряд функций автоматического импорта, характерных для CosmWasm. Объем импорта, вероятно, кажется огромным, но не волнуйтесь. REPL предназначен для выполнения всевозможных задач разработки и большей части импорта, который вам никогда не понадобится напрямую. А пока мы просто рассмотрим один класс из @ cosmwasm / sdk.

CosmWasmClient

CosmWasmClient - это точка входа высокого уровня для подключения к блокчейну с интегрированным модулем CosmWasm, например, CosmWasm демонет. И это выглядит так:

>> const client = new CosmWasmClient("https://lcd.demo-071.cosmwasm.com/")
undefined
>> await client.getChainId()
'testing'
>> await client.getHeight()
35266
>> await client.getBlock()
{
  id: 'FBEA10E503395FE950FE6E685880DD58BC1BE01B2FA2C02E0CDF7CA53B57A1AB',
  header: {
    version: { block: '10', app: '0' },
    time: '2020-03-06T09:34:06.932352209Z',
    height: 35268,
    chainId: 'testing'
  },
  txs: []
}

С помощью этих четырех команд вы создали экземпляр клиента для данной конечной точки, запросили идентификатор цепочки, высоту и последний блок. При вызове с аргументом высоты вы получаете конкретный блок.

>> await client.getBlock(2811)
{
  id: 'FD648FD18A2E9394097FE89343C9F1AA01380A34B569177789B608AC743146BF',
  header: {
    version: { block: '10', app: '0' },
    time: '2020-03-04T12:14:03.58338804Z',
    height: 2811,
    chainId: 'testing'
  },
  txs: [
    Uint8Array [
      230,   1,  40,  40,  22, 169,  10,  79, 122,  94, 123, 224,
       10,  20, 195, 135,  14,  74,  97,  17, 122, 250, 130, 153,
       31,  64,  47, 167, 122, 109, 145, 249, 232, 111,  18,  20,
      100, 179, 132, 115, 145, 240, 118, 218, 123, 209, 137,  92,
       54, 133,  79,  59,  90,  34, 110, 220,  26,  29, 123,  34,
      114, 101, 103, 105, 115, 116, 101, 114,  34,  58, 123,  34,
      110,  97, 109, 101,  34,  58,  34, 104, 101, 108, 108, 111,
       34, 125, 125,  18,  19,  10,  13,  10,   5, 117,  99, 111,
      115, 109,  18,   4,
      ... 132 more items
    ]
  ]
}

Этот блок включает транзакцию, которая возвращается в двоичном формате, который трудно проверить. Давайте попробуем найти транзакцию для той же высоты блока:

>> await client.searchTx({ height: 2811 })
[
  {
    height: 2811,
    hash: 'C77D63EAD29935C1EBB9CF6F38C28DAA28C9CCCBABDD3000D7049B46C8BA4238',
    rawLog: '[{"msg_index":0,"log":"","events":[{"type":"message","attributes":[{"key":"action","value":"execute"},{"key":"module","value":"wasm"},{"key":"signer","value":"cosmos1cwrsujnpz9a04q5eraqzlfm6dkgln6r05pyfmx"},{"key":"contract_address","value":"cosmos1vjecguu37pmd577339wrdp208ddzymkudc46zj"}]}]}]',
    logs: [ [Object] ],
    tx: { type: 'cosmos-sdk/StdTx', value: [Object] },
    timestamp: '2020-03-04T12:14:03Z'
  }
]

Лучше. Мы видим транзакцию в свойстве tx, но его значение не печатается. Давайте копаться:

>> const results = await client.searchTx({ height: 2811 })
undefined
>> results[0].tx.value
{
  msg: [ { type: 'wasm/execute', value: [Object] } ],
  fee: { amount: [ [Object] ], gas: '200000' },
  signatures: [
    {
      pub_key: [Object],
      signature: 'bjR5M7VFsfrj10pbfIsgYrUXs+20eEdFWpFIhvGwKqhyG+6A9I+u/Bm6O3tjcHLtteEHGRBJ4Cn3N3ZgYWMfJA=='
    }
  ],
  memo: 'Buying my name'
}
>> results[0].tx.value.msg[0]
{
  type: 'wasm/execute',
  value: {
    sender: 'cosmos1cwrsujnpz9a04q5eraqzlfm6dkgln6r05pyfmx',
    contract: 'cosmos1vjecguu37pmd577339wrdp208ddzymkudc46zj',
    msg: { register: [Object] },
    sent_funds: []
  }
}

Сообщение типа wasm/execute - это сообщение Cosmos SDK, содержащее адрес смарт-контракта и сообщение, которое было отправлено в контракт, а именно:

>> results[0].tx.value.msg[0].value.msg
{ register: { name: 'hello' } }

Коды, контракты и запросы

Мы можем получить список всех кодов (то есть байт-кодов WebAssembly), всех экземпляров данного кода и всю информацию для экземпляра контракта:

>> await client.getCodes()
[
  {
    id: 1,
    creator: 'cosmos1pkptre7fdkl6gfrzlesjjvhxhlc3r4gmmk8rs6',
    checksum: 'aff8c8873d79d2153a8b9066a0683fec3c903669267eb806ffa831dcd4b3daae',
    source: 'https://crates.io/api/v1/crates/cw-erc20/0.2.0/download',
    builder: 'confio/cosmwasm-opt:0.7.0'
  },
  {
    id: 2,
    creator: 'cosmos1pkptre7fdkl6gfrzlesjjvhxhlc3r4gmmk8rs6',
    checksum: 'd5dde423d321f7d3793a9b1667d06ac86c7f57dfbd2534a9c790963e1c2955ed',
    source: 'https://crates.io/api/v1/crates/cw-nameservice/0.2.0/download',
    builder: 'confio/cosmwasm-opt:0.7.0'
  }
]
>> await client.getContracts(2)
[
  {
    address: 'cosmos1vjecguu37pmd577339wrdp208ddzymkudc46zj',
    codeId: 2,
    creator: 'cosmos1pkptre7fdkl6gfrzlesjjvhxhlc3r4gmmk8rs6',
    label: 'Free'
  },
  {
    address: 'cosmos1ym5m5dw7pttft5w430nxx6uat8f84ck4algmhg',
    codeId: 2,
    creator: 'cosmos1pkptre7fdkl6gfrzlesjjvhxhlc3r4gmmk8rs6',
    label: 'Luxury'
  }
]
>> await client.getAccount("cosmos1ym5m5dw7pttft5w430nxx6uat8f84ck4algmhg")
{
  address: 'cosmos1ym5m5dw7pttft5w430nxx6uat8f84ck4algmhg',
  balance: [ { denom: 'ucosm', amount: '8000000' } ],
  pubkey: undefined,
  accountNumber: 14,
  sequence: 0
}

То, что мы видим в последнем вызове, - это контракт, который владеет 8 токенами COSM. Контракт службы имен (Код # 2) имеет интеллектуальный запрос для разрешения имен (который указан в устрашающей схеме JSON), который может быть выполнен следующим образом:

>> await client.queryContractSmart("cosmos1ym5m5dw7pttft5w430nxx6uat8f84ck4algmhg", { "resolverecord": { "name": "hello" }})
Uint8Array [
  123,  34,  97, 100, 100, 114, 101, 115, 115,  34,
   58,  34,  99, 111, 115, 109, 111, 115,  49,  55,
  113, 103, 100, 120, 121, 116, 103, 121, 103, 122,
   53,  52, 101, 116, 112, 113,  52, 110, 107, 109,
  112, 116, 102, 108,  53,  99,  51, 114, 108,  56,
  122, 113, 119,  57,  99,  97, 117,  34, 125
]

Для этого контракта результирующие двоичные данные представляют собой некоторый JSON, который мы можем изучить:

>> const data = await client.queryContractSmart("cosmos1ym5m5dw7pttft5w430nxx6uat8f84ck4algmhg", { "resolverecord": { "name": "hello" }})
undefined
>> JSON.parse(fromUtf8(data))
{ address: 'cosmos17qgdxytgygz54etpq4nkmptfl5c3rl8zqw9cau' }

Мы видели, как использовать CosmWasmClient для взаимодействия с блокчейном в режиме только для чтения. Следите за обновлениями, чтобы узнать, как CosmWasmClient можно использовать для загрузки, создания и выполнения смарт-контрактов.

Обновлено 2020–04–17: измените URL-адрес демона с https://lcd.demo-07.cosmwasm.com/ на https://lcd.demo-071.cosmwasm.com/