Este artigo usa a ethers
biblioteca como a implementação subjacente e descreve as propriedades detalhadas do objeto de transação Ethereum criado em Javascript. Este artigo pressupõe que o leitor tenha um certo conhecimento básico de Ethereum.
1. O que é uma ethers
biblioteca
O que se segue é uma introdução original de seu documento:
A biblioteca ethers.js pretende ser uma biblioteca completa e compacta para interagir com o Ethereum Blockchain e seu ecossistema. Ele foi originalmente projetado para uso com ethers.io e desde então se expandiu para uma biblioteca de uso muito mais geral.
O significado aproximado é ethers.js
uma biblioteca completa e compacta aplicada ao Ethereum e seu ecossistema. Ele foi originalmente projetado para ser usado em ethers.io e lentamente expandido em uma biblioteca multifuncional.
ethers
A biblioteca possui as seguintes características:
- A chave privada é armazenada no cliente, segura e livre de riscos
- Suporte para importação e exportação de carteiras em formato json (pode ser usado para Geth ou Paridade)
- Suporte para importação e exportação de palavras mnemônicas e carteira de hardware, palavras mnemônicas suportam vários idiomas
- Suporta vários formatos ABI, incluindo ABIv2 e ABI legível por humanos
- Suporta várias maneiras de se conectar a nós Ethereum, como JSON-RPC, INFURA, Etherscan ou MetaMask.
- Os nomes ENS são totalmente suportados como a primeira categoria de elementos
- A biblioteca é muito pequena (versão não compactada de 284kb, versão compactada de 88kb)
- Funções completas para atender a todas as suas necessidades para Ethereum
- Documentação detalhada
- Adicionados muitos casos de teste
- TypeScript legível
- Certificado MIT (incluindo suas dependências), totalmente de código aberto
Em segundo lugar, construa um objeto comercial
Em ethers.js
, um objeto de transação Ethereum é um objeto comum {}
, que contém os seguintes atributos opcionais:
- para
- gasLimit
- gasPrice
- nonce
- dados
- valor
- chainId
Os atributos acima são todos opcionais, o que significa que podem ser omitidos, mas não todos, deve haver pelo menos um atributo. Criamos um objeto de transação da seguinte maneira:
// All properties are optional
let transaction = {
nonce: 0,
gasLimit: 21000,
gasPrice: utils.bigNumberify("20000000000"),
to: "0x88a5C2d9919e46F883EB62F7b8Dd9d0CC45bc290",
// ... or supports ENS names
// to: "ricmoo.firefly.eth",
value: utils.parseEther("1.0"),
data: "0x",
// This ensures the transaction cannot be replayed on different networks
chainId: ethers.utils.getNetwork('homestead').chainId
}
Abaixo, explicamos esses atributos por meio de transações reais na rede de teste Kovan.
3. Explicação detalhada dos atributos do objeto de transação
Existem os seguintes trechos de código, nós modificaremos ou adicionaremos a este trecho em transações futuras. Esta é uma transação que cria um contrato:
let data='0x60....'
let provider = ethers.getDefaultProvider('kovan')
let wallet_new = wallet.connect(provider)
let trans = {
data:inputData
}
wallet_new.sendTransaction(trans).then( tx => {
console.log(tx)
}).catch( err => {
console.log(err)
})
Como você pode ver, nosso objeto de transação tem apenas um atributo data
e seu valor é o bytecode para criar o contrato. Nota: O bytecode ao criar o contrato não é o bytecode compilado pelo contrato de criação, mas o bytecode que pode ser obtido executando o bytecode do contrato criado.
Vamos dar uma olhada na resposta da transação impressa (Transaction Response):
você pode ver que no objeto de resposta da transação, além dos to
atributos, existem outros atributos. Portanto, o atributo mencionado acima pode ser omitido significa que ele pode ser omitido ao construir o objeto de transação. Se omitido, a ethers
biblioteca subjacente irá configurá-lo automaticamente para você. Vamos começar com este objeto de negociação mais simples, aumentar e explicar suas propriedades passo a passo.
3,1 to
Já que o to
atributo é null
, começaremos com o to
atributo. to
Representa o endereço do receptor na transação.
Uma transação no Ethereum deve ter um iniciador (conta externa, conta sem contrato), normalmente from
. Porque a ethers
biblioteca que usamos usa a carteira para assinar transações, então quem assina é quem assina from
. A transação geralmente tem um destinatário (conta externa e conta do contrato), ou seja to
. Por que isso é normal? Porque, como nosso exemplo agora, não há recebedor quando o contrato é criado. Embora o endereço do contrato seja to
retornado como um atributo após a criação do contrato , esse to
endereço está vazio quando é criado . Vamos dar uma olhada na captura de tela do etherscan para aprofundar essa impressão:
você pode ver que depois que a transação é executada, este to
atributo é o endereço do novo contrato. Deixe-me acrescentar que o endereço do contrato é calculado com base no endereço do chamador e no número de transações (nonce) que o chamador concluiu. Portanto, antes da implantação efetiva de um contrato, o endereço é definido e pode ser obtido.
Para resumir, o to
atributo é o endereço do receptor na transação. Especificamente: se você estiver transferindo ETH para uma conta externa, é o endereço de recebimento da ETH; se você estiver chamando um contrato (transferir ETH para uma conta de contrato também é um contrato de chamada), é o endereço do contrato; se você estiver criando um contrato, porque não há nenhum destinatário no momento, Basta padronizá-lo.
3,2 data
Em seguida, falar sobre o código acima usa a propriedade: data
. Durante a transação, podemos enviar dados da transação junto com a transação. Os dados de transação podem ser chamadas de método para o contrato ou alguns dados sem sentido, que às vezes são chamados payload
. No exemplo acima, data
o valor do atributo é o bytecode do contrato que criamos. Vamos adicionar um to
atributo ao objeto de transação acima e modificar data
o valor do atributo:
let trans = {
data:"0x496c6f7665457468657265756d",
to:"0xDD55634e1027d706a235374e01D69c2D121E1CCb"
}
Aqui to
está um endereço de conta externa, que data
é a string "I love Ethereum" convertida em valor hexadecimal ( data
deve 0x
começar com). A resposta após o envio da transação é a seguinte:
Vamos ver o resultado no etherscan:
A partir do trecho de código, podemos ver que enviamos diretamente uma mensagem (string) para uma conta. Na parte inferior de InputData, ele exibe dados nativos por padrão. Selecione View Input As UTF-8, e IloveEthereum será exibido. Nenhum espaço é mostrado aqui porque a ferramenta que usei não codificava espaços. Essa função de enviar uma string para uma conta parece enviar uma mensagem curta para um número de telefone celular? Você pode até enviar um artigo (mas com muitas taxas), o Ethereum é interessante?
Se os dados enviados são os dados quando o método de contrato é chamado, geralmente têm um formato fixo e não podem ser dados arbitrários. Os exemplos são os seguintes:
data:0x07391dd6000000000000000000000000000000000000000000000000000000000000000a
Aqui, os primeiros 8 bits 07391dd6
dos primeiros 32 bytes são seletores de função e, após 32 bytes, estão os dados do tipo correspondente. Os leitores interessados podem ler artigos relacionados na codificação Ethereum por conta própria.
Bem, para resumir: o data
atributo são os dados enviados com a chamada. Se o objeto chamado for um contrato, geralmente é o código do método de chamada do contrato; se for para criar um contrato, é o bytecode criado; se o objeto chamado for uma conta externa, o conteúdo desses dados é arbitrário (a conta externa não tem código , E não executará os dados enviados).
3,3 value
value
O atributo representa a quantidade de Ether enviada com esta transação. Independentemente de o tipo de transação ser transferência direta de ETH (incluindo transferência para o contrato e transferência para uma conta externa), criação de um contrato (neste caso, ETH será usada como a ETH inicial do contrato criado) ou chamada de contrato (o método de contrato é payable
), é registrado fielmente A quantidade de ETH que você enviou na transação (sem incluir a taxa de manuseio, a taxa de manuseio é um consumo adicional). Vamos apenas adicionar uma value
propriedade do objeto de transação , seu valor são wei
unidades de atenção . E geralmente quando estamos em uma referência geral às ether
unidades monetárias Ethernet , precisamos fazer uso de uma conversão.
let trans = {
data:"0x496c6f7665457468657265756d",
value:ethers.utils.parseEther('0.1'),
to:"0xDD55634e1027d706a235374e01D69c2D121E1CCb"
}
value
O valor no código é 0,1 ETH. Vamos enviar esta transação:
Em JS, se o número for relativamente grande, ele excederá o limite superior da representação decimal js (cerca de 10 ** 15), então BigNumber é geralmente usado para interagir com Ethereum. Você pode ver que o número de WEI enviado é convertido em um BigNumber. Vejamos o resultado do etherscan novamente:
ele não é mostrado aqui data
porque não cliquei em Clique para ver mais para expandir. Como você pode ver, enviamos 0,1 ETH com a transação.
3.4 gasLimit
egasPrice
A seguir, apresentaremos dois atributos relacionados ao gás: gasLimit
e gasPrice
. Isso gasLimit
se refere ao consumo máximo de gás da transação e gasPrice
ao preço que você está disposto a pagar pelo gás efetivamente consumido. A quantidade específica de gás consumido é multiplicada pela gasPrice
taxa que você está disposto a pagar ao minerador. Após a transação ser executada, o gás não consumido será devolvido a você (a situação do erro de transação não será discutida aqui, neste caso às vezes o gás não consumido não será reembolsado).
gasLimit
Normalmente usado para limitar uma determinada transação não pode consumir muitos recursos. Aqui está um cenário de uso: Muitas vezes usamos MetaMask para transferir fundos diretamente para contas externas. O gasLimit
valor padrão no MetaMask é 23.000 , e o mínimo não pode ser inferior a 21.000.
Vejamos uma transação de transferência específica no etherscan:
Como você pode ver na figura acima, quando não enviamos nenhum dado com a transação (o data
atributo está vazio, se não estiver vazio, gás adicional será consumido), para um externo A transferência da conta consumirá 21 mil gás, o que é basicamente fixo. Portanto, o gasLimit
limite superior desta transação também é definido 21000
, a taxa de utilização 100%
.
O nosso na foto acima gasPrice
é 5 Gwei
. Quanto mais alto o preço oferecido, mais rápida será a transação e, claro, maior será sua taxa de manuseio. Normalmente gasPrice
, quando falamos sobre isso, todos nós o usamos Gwei
como uma unidade, mas ainda temos que convertê-lo quando o usamos wei
. Este 5 Gwei
multiplicado pelo gás consumido 21000
é exatamente o que é mostrado na figura acima Transaction Fee
: 0.000105
ETH. Quando o autor escreve aqui, o preço da ETH gira em torno de US $ 205, então a taxa de manuseio para o envio é de cerca de 0.15RMB
.
Vamos adicionar esses dois atributos ao objeto de transação para ver se o excesso de gás é consumido. Nossa gasLimit está definido para 100000
, gasPrice
definida como 3 Gwei
, vamos reenviar a transação:
let trans = {
data:"0x496c6f7665457468657265756d",
value:ethers.utils.parseEther('0.1'),
gasLimit:100000,
gasPrice:ethers.utils.parseUnits("3",'gwei'),
to:"0xDD55634e1027d706a235374e01D69c2D121E1CCb"
}
Aqui, como o nosso gasLimit
não pode exceder o limite decimal de JS, o sistema decimal é usado diretamente 100000
. A resposta da transação é:
olhamos diretamente para o resultado da transação no etherscan:
como enviamos I love Ethereum
esta string com a transação , consumimos 208 mais gás. De acordo com a taxa que deduzimos, o gás não utilizado não está incluído no custo.
Para gasLimit
falar geralmente em uso ethers
, não é necessário definir a biblioteca, deixe-o como padrão na linha. Se quiser defini-lo manualmente, você pode usá-lo para estimar primeiro e, em seguida, expandi-lo para cima de forma adequada, como o seguinte snippet de código:
let args = [_address,amount]
let gasLimit = await contract.estimate.transfer(...args)
let step = ethers.utils.bigNumberify(1000)
gasLimit = gasLimit.add(step)
Para gasPrice
falar, geralmente definido como 5 Gwei
ou em circunstâncias normais 6 Gwei
. Pode ser definido como 1.5 Gwei
ou quando o gás consumir muito ou a rede estiver ociosa 2 Gwei
. No entanto, o tempo de transação será estendido dessa forma e pode até falhar. Se você quiser negociar rapidamente, defina-o como 10 Gwei
ou 20 Gwei
até mais alto, mas isso custará mais. Se você tiver mais dinheiro, será rápido e, se não tiver dinheiro suficiente, será lento. E tenha cuidado: uma taxa muito baixa pode fazer com que nenhum mineiro empacote a transação, e a transação irá falhar. Claro, se você estiver no testnet, você pode definir um valor mais alto, porque você não precisa realmente gastar dinheiro.
3,5 nonce
No objeto de transação, nonce
representa o número de transações concluídas pelo endereço. Começa em 0 e é um número inteiro que aumenta automaticamente. Normalmente, não precisamos defini-lo. Mas em alguns casos especiais, ele pode ser definido manualmente. Um cenário é ao cobrir transações. Você pode definir manualmente o nonce para o valor nonce de uma transação que foi enviada, mas ainda não concluída, para substituir a transação. Normalmente, o objetivo disso é acelerar a transação (aumentar gasPrice
) ou usar completamente uma nova transação. Isso também é fácil de entender. Por exemplo, minha transação nº 122 é enviar uma ETH para A, mas antes que esta transação não seja enviada ou concluída, fiz uma modificação urgente para alterar esta transação nº 122 para enviar uma ETH para B. Nesse ponto, só preciso definir o nonce da nova transação como 122.
Se você deseja definir no objeto de transação que você normalmente usa, você precisa consultar o número de transações concluídas.Este número é o valor nonce que você deve usar. Use o seguinte código:
let address = "0x02F024e0882B310c6734703AB9066EdD3a10C6e0";
provider.getTransactionCount(address).then((transactionCount) => {
console.log("Total Transactions Ever Sent: " + transactionCount);
});
É importante notar que: nonce tem um uso especial, você pode especificar um valor futuro. Por exemplo, se o número de transações que você concluiu atualmente é 2096, o valor do nonce para a próxima transação deve ser 2097. Neste ponto, você também pode pular 2097 e defini-lo como 2098, então o que acontecerá? Neste momento, a transação de número 2098 é equivalente a uma transação atrasada, que será enviada, mas não será executada, e você não poderá consultá-la no etherscan. Em seguida, realizamos uma transação normal com o valor nonce definido como 2097, e a transação será enviada e executada. Aí vem o ponto importante: no próximo bloco, a transação com um nonce de 2098 também será executada (porque 2097 já foi executada, é a sua vez).
3,6 chainId
chainId
Representa o ID de rede com o qual você deseja iniciar uma transação. Pegue a rede principal e as três principais redes de teste como exemplos. A rede principal (mas ethers
ainda chamada de homestead
casa na China) é 1, a Ropsten
rede de teste é 3, a Rinkeby
rede de teste é 4 e a Kovan
rede de teste é 42. A rede personalizada pode ser configurada por você, etc.
De modo geral, não há necessidade de configurar isso ao usar a carteira chainId
. Como o login da carteira irá vincular uma rede, é a rede de seu objeto de transação. Mas você também pode definir manualmente um valor específico para evitar transações na rede errada. Você pode usar diretamente o valor numérico decimal acima ou pode usar ethers
o código de amostra em:
chainId: ethers.utils.getNetwork('homestead').chainId
Se estivermos negociando na rede de teste Kovan, os parâmetros do método devem ser alterados kovan
. Vamos adicionar chainId
e nonce
à transação. E altere o valor para 0,01ETH para distinguir.
let count = await provider.getTransactionCount(wallet_new.address)
let trans = {
data:"0x496c6f7665457468657265756d",
value:ethers.utils.parseEther('0.01'),
gasLimit:100000,
nonce: count,
chainId:ethers.utils.getNetwork('kovan').chainId,
gasPrice:ethers.utils.parseUnits("3",'gwei'),
to:"0xDD55634e1027d706a235374e01D69c2D121E1CCb"
}
Aqui está a resposta da transação:
Como os números 2097 e 2098 nonce
são consumidos ao usar valores futuros , o número agora é 2099. Vamos dar uma olhada nos resultados no etherscan:
você pode ver que a quantidade de ETH enviada é 0,01 ETH e o nonce é 2099. Alguém pode perguntar por que ele não é exibido no etherscan chainId
, porque o etherscan é dividido em vários sites com base na mainnet e testnet, e cada site exibe apenas transações em sua própria rede. Por exemplo, o URL real do etherscan que visitei é:
https://kovan.etherscan.io/tx/0x4db8e6b4096d6c27be341b73af99a8d0477e19ba483248c1fdb6fb431fbb3646
Todas as transações mostradas neste site chainId
são 42.
Quatro, resumo
Neste artigo, fornecemos uma introdução detalhada às propriedades específicas do objeto de transação Ethereum criado manualmente. Esses atributos podem ser omitidos, mas não podem ser omitidos (porque não faz sentido omitir todos eles). Os mais comumente usados são to
, value
e data
atributos. Nota: Este é apenas um atributo que precisa ser definido ao criar manualmente um objeto de transação no código; se você usar diretamente uma carteira comum (como MetaMask ou Trust wallet), a carteira terá uma interface de IU para ajudá-lo a configurar tudo. No entanto, é necessário esclarecer a base da implementação.Espero que este artigo possa fornecer uma ajudinha aos desenvolvedores do Ethereum.
Você pode deixar uma mensagem para apontar erros ou sugerir melhorias.