
Neste artigo, veremos dois exemplos de como escrever um contrato inteligente em C ++ usando o
WASM com base na rede blockchain da Ontology. Hoje, após vários meses de operação estável no modo de teste, a
Ontology lançou o WASM na rede principal, o que permite transferir contratos do dApp com lógica de negócios complexa para o blockchain sem dor e a um custo menor, enriquecendo significativamente o ecossistema do dApp.
O Ontology Wasm também suporta a criação de contratos inteligentes na linguagem Rust, você pode ler sobre isso
aqui .
Abaixo estão dois exemplos de um contrato inteligente: primeiro, escreva "Olá, mundo!" e, em seguida, crie um envelope de dinheiro virtual que possa ser enviado a um amigo como presente.
Desenvolvimento de um contrato WASM usando C ++
Exemplo 1. Olá Mundo
Vamos começar com o Hello World:
#include<ontiolib/ontio.hpp> #include<stdio.h> using namespace ontio; class hello:public contract { public: using contract::contract: void sayHello(){ printf("hello world!"); } }; ONTIO_DISPATCH(hello, (sayHello));
Criação de contrato
O compilador
Ontology Wasm CDT contém um ponto de entrada e parâmetros de análise, para que os desenvolvedores não precisem redefinir os métodos de entrada. Além disso, para escrever a lógica do serviço, você pode chamar os métodos de API do contrato inteligente.
ONTIO_DISPATCH(hello, (sayHello));
No exemplo acima, apoiamos apenas o sayHello até agora:
printf("hello world!");
"Olá, mundo!" será exibido no log do nó de depuração. Ao escrever um contrato inteligente diretamente, printf pode ser usado apenas para depuração, pois o próprio contrato inteligente contém comandos mais funcionais.
API de contrato inteligente
O Ontology Wasm fornece as seguintes APIs para interagir com o blockchain do servidor:

Exemplo 2: Envelope para dinheiro
Agora, vejamos um exemplo mais complexo usando a API de contrato inteligente do Wasm.
Neste exemplo, escreveremos um envelope virtual em dinheiro, um análogo do envelope vermelho (hongbao) é uma função popular do mensageiro chinês Wechat, que permite enviar dinheiro para amigos em um bate-papo. O usuário recebe uma mensagem na forma de um envelope vermelho, abre-a e o dinheiro é creditado automaticamente no saldo da conta.
Como parte de um contrato inteligente, os usuários podem usar esse contrato para enviar tokens ONT, ONG ou OEP-4 usando envelopes de dinheiro virtual para seus amigos, que podem transferir tokens para suas carteiras blockchain.
Preparando para criar um contrato
Primeiro, crie o arquivo do contrato de origem e nomeie-o redEnvelope.cpp. Em seguida, precisamos de três APIs para este contrato:
- createRedEnvelope : Criar um envelope de dinheiro
- queryEnvelope : Solicitar informações do envelope
- ClaimEnvelope : abra um envelope e receba dinheiro
#include<ontiolib/ontio.hpp> using namespace ontio; class redEnvlope: public contract{ } ONTIO_DISPATCH(redEnvlope, (createRedEnvlope)(queryEnvlope)(claimEnvelope));
Agora precisamos salvar o valor-chave. Em um contrato inteligente, os dados são armazenados no contexto do contrato como valor-chave e precisamos adicionar um prefixo aos dados KEY para uma solicitação subsequente.
Abaixo, definimos três prefixos que usaremos:
std::string rePrefix = "RE_PREFIX_"; std::string sentPrefix = "SENT_COUNT_"; std::string claimPrefix = "CLAIM_PREFIX_";
Como o contrato suporta tokens de Ontologia - ONT e ONG, podemos determinar o endereço do contrato com antecedência. Diferentemente de um contrato inteligente padrão, o endereço do contrato da Ontology é fixo e não é derivado do hash do contrato.
address ONTAddress = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}; address ONGAddress = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2};
Em seguida, é necessário salvar as informações sobre o token usado no contrato: o endereço do token do contrato, a quantidade total do envelope e o número de envelopes.
struct receiveRecord{ address account;
A seguir, é apresentada a operação de macro definida pelo Ontology Wasm CDT, usado para serialização antes da estruturação dos dados.
ONTLIB_SERIALIZE(receiveRecord,(account)(amount))
Criando um envelope
Agora que concluímos os preparativos necessários, iniciaremos o desenvolvimento da lógica da API.
1. Ao criar um envelope monetário, é necessário indicar o endereço do proprietário, o número e a quantidade de envelopes, bem como o endereço do token:
bool createRedEnvlope(address owner,asset packcount, asset amount,address tokenAddr ){ return true; }
2. Verifique a assinatura do proprietário, caso contrário, reverteremos (reverter a transação) e sairemos:
ontio_assert(check_witness(owner),"checkwitness failed");
Nota : ontio_assert (expr, errormsg): false expr retorna um erro e sai do contrato.
3. Se um token ONT for usado em um envelope, é importante lembrar que o ONT não está fragmentado (pelo menos 1 ONT). Em seguida, o valor total do envelope monetário deve ser maior ou igual ao número de tokens para garantir que haja pelo menos 1 ONT em cada envelope:
if (isONTToken(tokenAddr)){ ontio_assert(amount >= packcount,"ont amount should greater than packcount"); }
4. Em seguida, determinamos para o titular do envelope o número total de envelopes de dinheiro que ele envia:
key sentkey = make_key(sentPrefix,owner.tohexstring()); asset sentcount = 0; storage_get(sentkey,sentcount); sentcount += 1; storage_put(sentkey,sentcount);
5. Gere o hash do envelope - o identificador que marca esse envelope:
H256 hash ; hash256(make_key(owner,sentcount),hash) ; key rekey = make_key(rePrefix,hash256ToHexstring(hash));
6. Nós traduziremos os tokens no contrato. Descobrimos o endereço do contrato que está sendo executado atualmente usando o comando self_address (), depois transferiremos a quantidade atribuída de tokens para o contrato com base no tipo de tokens:
address selfaddr = self_address(); if (isONTToken(tokenAddr)){ bool result = ont::transfer(owner,selfaddr ,amount); ontio_assert(result,"transfer native token failed!"); }else if (isONGToken(tokenAddr)){ bool result = ong::transfer(owner,selfaddr ,amount); ontio_assert(result,"transfer native token failed!"); }else{ std::vector<char> params = pack(std::string("transfer"),owner,selfaddr,amount); bool res; call_contract(tokenAddr,params, res ); ontio_assert(res,"transfer oep4 token failed!"); }
Nota 1: para ONT e ONG, o Ontology Wasm CDT fornece a API ont :: transfer para transferir tokens; Os tokens OEP-4 devem ser enviados usando o método de chamada convencional de contrato cruzado.
Nota 2: como um endereço de carteira comum, o endereço do contrato pode aceitar qualquer tipo de token. No entanto, o endereço do contrato é gerado por um hash binário compilado e, portanto, não possui uma chave privada correspondente e não pode usar tokens de contrato. Se você não configurou uma chave privada, não poderá gerenciar esses tokens.
7. Salve as informações sobre o contrato no armazém de dados:
struct envlopeStruct es ; es.tokenAddress = tokenAddr; es.totalAmount = amount; es.totalPackageCount = packcount; es.remainAmount = amount; es.remainPackageCount = packcount; es.records = {}; storage_put(rekey, es);
8. Envie uma notificação sobre a criação do envelope. Este é um processo assíncrono para chamar um contrato inteligente; o contrato também enviará uma notificação do resultado da execução. O formato de execução pode ser determinado pelo autor do contrato.
char buffer [100]; sprintf(buffer, "{\"states\":[\"%s\", \"%s\", \"%s\"]}","createEnvlope",owner.tohexstring().c_str(),hash256ToHexstring(hash).c_str()); notify(buffer); return true;
Viva, o envelope de dinheiro está quase pronto. Agora vamos ver como solicitar informações sobre o envelope.
Envelope de consulta (consulta
A lógica da solicitação é bastante simples, você só precisa obter as informações e o formato do repositório de dados e depois gerar:
std::string queryEnvlope(std::string hash){ key rekey = make_key(rePrefix,hash); struct envlopeStruct es; storage_get(rekey,es); return formatEnvlope(es); }
Nota: para operações de contrato inteligente somente leitura (por exemplo, consulta), você pode verificar o resultado por meio de pré-execução. Ao contrário de uma chamada de contrato regular, o pré-executivo não exige uma assinatura de carteira e, portanto, não exige uma comissão na ONG. Depois disso, outros usuários poderão solicitar o envelope se tiverem um hash de envelope (ID do envelope).
Envelope de recebimento
Nesse estágio, já transferimos tokens para um contrato inteligente, agora, para que seus amigos possam reivindicar com êxito um compartilhamento no envelope, você precisa enviar a eles o identificador de envelope (hash).
1. Para receber um envelope, você deve digitar o endereço da sua conta e o hash do envelope:
bool claimEnvlope(address account, std::string hash){ return true; }
2. Em seguida, o contrato verificará a assinatura da sua conta para garantir que você seja o proprietário. Cada conta pode solicitar um envelope apenas uma vez:
ontio_assert(check_witness(account),"checkwitness failed"); key claimkey = make_key(claimPrefix,hash,account); asset claimed = 0 ; storage_get(claimkey,claimed); ontio_assert(claimed == 0,"you have claimed this envlope!");
3. Verifique se o envelope é recebido de acordo com as informações de hash recebidas da loja:
key rekey = make_key(rePrefix,hash); struct envlopeStruct es; storage_get(rekey,es); ontio_assert(es.remainAmount > 0, "the envlope has been claimed over!"); ontio_assert(es.remainPackageCount > 0, "the envlope has been claimed over!");
4. Criando um registro de reivindicação:
struct receiveRecord record ; record.account = account; asset claimAmount = 0;
5. Cálculo da quantidade para cada requerente de envelope.
Para o último participante, a quantidade restante é determinada; para qualquer outro, a quantidade declarada é determinada por um número aleatório calculado pelo hash do bloco atual e pelas informações atuais sobre o envelope:
if (es.remainPackageCount == 1){ claimAmount = es.remainAmount; record.amount = claimAmount; }else{ H256 random = current_blockhash() ; char part[8]; memcpy(part,&random,8); uint64_t random_num = *(uint64_t*)part; uint32_t percent = random_num % 100 + 1; claimAmount = es.remainAmount * percent / 100;
6. Creditar fundos
A quantidade correspondente de tokens é transferida para a conta do requerente do envelope, de acordo com o resultado do cálculo:
address selfaddr = self_address(); if (isONTToken(es.tokenAddress)){ bool result = ont::transfer(selfaddr,account ,claimAmount); ontio_assert(result,"transfer ont token failed!"); } else if (isONGToken(es.tokenAddress)){ bool result = ong::transfer(selfaddr,account ,claimAmount); ontio_assert(result,"transfer ong token failed!"); } else{ std::vector<char> params = pack(std::string("transfer"),selfaddr,account,claimAmount); bool res = false; call_contract(es.tokenAddress,params, res ); ontio_assert(res,"transfer oep4 token failed!"); }
7. Anotaremos as informações sobre o recebimento de fundos e as informações atualizadas sobre o envelope no cofre e enviaremos uma notificação sobre o cumprimento do contrato:
storage_put(claimkey,claimAmount); storage_put(rekey,es); char buffer [100]; std::sprintf(buffer, "{\"states\":[\"%s\",\"%s\",\"%s\",\"%lld\"]}","claimEnvlope",hash.c_str(),account.tohexstring().c_str(),claimAmount); notify(buffer); return true;
Como mencionado acima, este contrato pode enviar tokens do contrato por meio da API claimEnvelope. Isso garante a segurança dos tokens enquanto estão no envelope, pois ninguém pode retirar ativos sem atender aos requisitos necessários.
Feito! Você escreveu seu primeiro contrato inteligente. O código completo do contrato pode ser encontrado no GitHub
aqui .
Teste de contrato
Há duas maneiras de verificar um contrato:
- Usar CLI
- Use o Golang SDK
Conclusão
Neste artigo, falamos sobre como escrever um contrato inteligente para o Ontolgy Wasm usando a API blockchain. Resta resolver o problema de privacidade para que o contrato inteligente se transforme em um produto completo. Nesse estágio do código, qualquer pessoa pode obter um hash do envelope vermelho rastreando os registros do contrato, o que significa que qualquer pessoa pode reivindicar uma participação no envelope. Esse problema pode ser resolvido de maneira simples - definimos uma lista de contas que podem solicitar um envelope quando ele é criado. Se desejar, esta função também pode ser testada.
Obtenha uma concessão de Ontologia para o desenvolvimento do dApp de US $ 20.000
Inscreva-se no Programa de Talentos
para Estudantes de Ontologia
Você é desenvolvedor? Participe da nossa comunidade de tecnologia no
Discord . Além disso, dê uma olhada no
Developer Center em nosso site, onde você pode encontrar ferramentas, documentação e muito mais para desenvolvedores.
Ontologia