Использование библиотек Ethereum для размещения Smart-контрактов на Moonbeam

Moonbeam in Russian
17 min readApr 9, 2021

--

Введение

В этом руководстве рассматривается использование компилятора Solidity и трех различных библиотек Ethereum для подписания и отправки транзакции в Moonbeam вручную. Данные три библиотеки являются:

Кроме того, для составления смарт-контракта будут использованы еще две другие библиотеки:

  • Solc-js для компиляции смарт-контрактов Solidity с использованием JavaScript
  • Py-solc-x для компиляции смарт-контрактов Solidity с использованием Python

Примечание: Примеры в этом руководстве предполагают, что у вас есть Ubuntu 18.04, и он должен быть адаптирован для MacOS или Windows.

Проверяем необходимые требования

К примеру, кто использует web3.js, ethers.js вам необходимо предварительно установить Node.js и NPM. Для web3.py вам понадобятся Python и PIP. На момент написания этого руководства использовались следующие версии:

  • Node.js v15.10.0
  • NPM v7.5.3
  • Python v3.6.9 (для web3 требуется Python> = 3.5.3 и <4)
  • PIP3 v9.0.1

Дальше, создайте папку для хранения всех соответствующих файлов:

mkdir incrementer && cd incrementer/

Для библиотек JavaScript сначала Вы можете создать простой файл package.json (не обязательно):

npm init --yes

В каталоге установите соответствующую библиотеку и компилятор Solidity (web3.py и py-solc-x устанавливаются по умолчанию в каталог PIP3):

  • Web3.js — npm i web3 npm i solc@0.8.0
  • Ethers.js — npm i ethers npm i solc@0.8.0
  • Web3.py — pip3 install web3 pip3 install py-solc-x

Версии, использованные при публикации этого руководства, были:

  • Web3.js v1.33 (npm ls web3)
  • Ethers.js v5.0.31 (npm ls ethers)
  • Solc (JS) v0.8.0 (npm ls solc)
  • Web3.py v5.17.0 (pip3 show web3)
  • Py-solc-x v1.1.0 (pip3 show py-solc-x)

Настройка для этого примера будет простой и будет содержать следующие файлы:

  • Incrementer.sol — файл с нашим кодом Solidity
  • compile. * — компилирует контракт с компилятором Solidity
  • deploy. *: он будет обрабатывать размещения на нашем локальной ноде Moonbeam
  • get. * — сделает ноду для получения текущего значения числа
  • increment.* — совершает транзакцию для увеличения числа, хранящегося в ноде Moonbeam
  • reset. * — функция, которая сбросит сохраненное число

Файл контракта

Используемый контракт представляет собой простой incrementer, произвольно названный Incrementer.sol, который вы можете найти здесь. Код Solidity следующий:

pragma solidity ^0.8.0;

contract Incrementer {
uint256 public number;

constructor(uint256 _initialNumber) {
number = _initialNumber;
}

function increment(uint256 _value) public {
number = number + _value;
}

function reset() public {
number = 0;
}
}

Функция constructorкоторая запускается при размещения контракта, устанавливает начальное значение числовой переменной, хранящейся в цепочке (по умолчанию 0). Функция incrementдобавляет предоставленное значение _valueк текущему числу, но необходимо отправить транзакцию, которая изменяет сохраненные данные. Наконец, функция resetсбрасывает сохраненное значение на ноль.

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

Компиляция смарт-контракта

Единственная цель файла компиляции — использовать компилятор Solidity для вывода байт-кода и интерфейса (ABI) нашего контракта. Вы можете найти фрагменты кода для каждой библиотеки здесь (они были произвольно названы compile.*):

Примечание: Файл компиляции для обеих библиотек JavaScript такой же, поскольку они используют привязки JavaScript для компилятора Solidity (один и тот же пакет).

Web3.js и Ethers.js

В первой части скрипта выбирается путь к контракту и читается его содержимое.

Затем создается входной объект компилятора Solidity, который передается в качестве входных данных функции solc.compile.

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

Web3.py

В первой части скрипта файл контракта компилируется с помощью функции solcx.compile_files . Обратите внимание, что файл контракта находится в том же каталоге, что и сценарий компиляции.

Примечание: При запуске compile.py вы можете получить сообщение об ошибке, в котором говорится, что необходимо установить Solc. Если это так, раскомментируйте строку в файле, который выполняет solcx.install_solc (), и повторно запустите файл компиляции с помощью python3 compile.py. Более подробную информацию можно найти по этой ссылке.

Затем, завершая сценарий, данные контракта экспортируются. В этом примере были определены только интерфейс (ABI) и байт-код.

Размещение смарт-контракта

Независимо от библиотеки, стратегия размещение скомпилированного смарт-контракта в чем-то похожа. Экземпляр контракта создается с использованием его интерфейса (ABI) и байт-кода. Из этого экземпляра функция размещения используется для отправки подписанной транзакции, которая размещается контракт. Здесь вы можете найти фрагменты кода для каждой библиотеки (они были произвольно названы deploy.*):

Для простоты файл размещения состоит из двух разделов. В первом разделе («Define Provider & Variables») импортируются используемая библиотека, а также ABI и байт-код контракта. Также определяются провайдер и учетная запись из (с закрытым ключом). Обратите внимание, что providerRPC имеет как стандартную конечную точку RPC автономного узла, так и конечную точку для Moonbase Alpha.

Web3.js

const Web3 = require('web3');
const contractFile = require('./compile');

/*
-- Define Provider & Variables --
*/
// Provider
const providerRPC = {
standalone: 'http://localhost:9933',
moonbase: 'https://rpc.testnet.moonbeam.network',
};
const web3 = new Web3(providerRPC.standalone); //Change to correct network

// Variables
const account_from = {
privateKey: 'YOUR-PRIVATE-KEY-HERE',
address: 'PUBLIC-ADDRESS-OF-PK-HERE',
};
const bytecode = contractFile.evm.bytecode.object;
const abi = contractFile.abi;

/*
-- Deploy Contract --
*/
const deploy = async () => {
console.log(`Attempting to deploy from account ${account_from.address}`);

// Create Contract Instance
const incrementer = new web3.eth.Contract(abi);

// Create Constructor Tx
const incrementerTx = incrementer.deploy({
data: bytecode,
arguments: [5],
});

// Sign Transacation and Send
const createTransaction = await web3.eth.accounts.signTransaction(
{
data: incrementerTx.encodeABI(),
gas: await incrementerTx.estimateGas(),
},
account_from.privateKey
);

// Send Tx and Wait for Receipt
const createReceipt = await web3.eth.sendSignedTransaction(
createTransaction.rawTransaction
);
console.log(
`Contract deployed at address: ${createReceipt.contractAddress}`
);
};

deploy();

Ethers.js

const ethers = require('ethers');
const contractFile = require('./compile');

/*
-- Define Provider & Variables --
*/
// Provider
const providerRPC = {
standalone: {
name: 'moonbeam-standalone',
rpc: 'http://localhost:9933',
chainId: 1281,
},
moonbase: {
name: 'moonbase-alpha',
rpc: 'https://rpc.testnet.moonbeam.network',
chainId: 1287,
},
};
const provider = new ethers.providers.StaticJsonRpcProvider(
providerRPC.standalone.rpc,
{
chainId: providerRPC.standalone.chainId,
name: providerRPC.standalone.name,
}
); //Change to correct network

// Variables
const account_from = {
privateKey: 'YOUR-PRIVATE-KEY-HERE',
};
const bytecode = contractFile.evm.bytecode.object;
const abi = contractFile.abi;

// Create Wallet
let wallet = new ethers.Wallet(account_from.privateKey, provider);

/*
-- Deploy Contract --
*/
// Create Contract Instance with Signer
const incrementer = new ethers.ContractFactory(abi, bytecode, wallet);

const deploy = async () => {
console.log(`Attempting to deploy from account: ${wallet.address}`);

// Send Tx (Initial Value set to 5) and Wait for Receipt
const contract = await incrementer.deploy([5]);
await contract.deployed();

console.log(`Contract deployed at address: ${contract.address}`);
};

deploy();

Web3.py

from compile import abi, bytecode
from web3 import Web3

#
# -- Define Provider & Variables --
#
# Provider
provider_rpc = {
'standalone': 'http://localhost:9933',
'alphanet': 'https://rpc.testnet.moonbeam.network',
}
web3 = Web3(Web3.HTTPProvider(provider_rpc['standalone'])) # Change to correct network

# Variables
account_from = {
'private_key': 'YOUR-PRIVATE-KEY-HERE',
'address': 'PUBLIC-ADDRESS-OF-PK-HERE',
}

#
# -- Deploy Contract --
#
print(f'Attempting to deploy from account: { account_from["address"] }')

# Create Contract Instance
Incrementer = web3.eth.contract(abi=abi, bytecode=bytecode)

# Build Constructor Tx
construct_txn = Incrementer.constructor(5).buildTransaction(
{
'from': account_from['address'],
'nonce': web3.eth.getTransactionCount(account_from['address']),
}
)

# Sign Tx with PK
tx_create = web3.eth.account.signTransaction(construct_txn, account_from['private_key'])

# Send Tx and Wait for Receipt
tx_hash = web3.eth.sendRawTransaction(tx_create.rawTransaction)
tx_receipt = web3.eth.waitForTransactionReceipt(tx_hash)

print(f'Contract deployed at address: { tx_receipt.contractAddress }')

Web3.js

В первой части скрипта (или провайдер) web3 создается с помощью конструктора Web3 с провайдером RPC. Изменяя RPC вы можете выбрать, в какую сеть вы хотите отправить транзакцию.

Закрытый ключ связанный с ним и общедоступный адрес определяются для подписания транзакции и ведения журнала. Требуется только закрытый ключ. Кроме того, байт-код и интерфейс контракта (ABI) извлекаются из экспорта компиляции.

Во втором разделе создается экземпляр контракта, предоставляя ABI. Затем используется функция размещения, которой требуются байт-код и аргументы функции-конструктора. Это генерирует boject транзакции.

После этого транзакцию можно подписать с помощью метода web3.eth.accounts.signTransaction (). Поле данные соответствуют байт-коду, а входные аргументы конструктора кодируются вместе. Обратите внимание, что значение газа получается с использованием опции EstimationGas () внутри транзакции конструктора.

Ethers.js

В первой части сценария можно указать разные сети с помощью имени, URL-адреса RPC (обязательно) и идентификатора цепочки. Провайдер (аналогичный экземпляру web3) создается с помощью метода ethers.providers.StaticJsonRpcProvider. Альтернативой является использование метода ethers.providers.JsonRpcProvide (providerRPC), который требует только адрес конечной точки RPC поставщика. Но это могло создать проблемы совместимости с индивидуальными спецификациями проекта.

Закрытый ключ определяется для создания экземпляра кошелька, для которого также требуется поставщик из предыдущего шага. Экземпляр кошелька используется для подписи транзакций. Кроме того, байт-код и интерфейс контракта (ABI) извлекаются из экспорта компиляции.

Во втором разделе создается экземпляр контракта с помощью ethers.ContractFactory (), предоставляющий ABI, байт-код и кошелек. Таким образом, у экземпляра контракта уже есть подписывающая сторона. Затем используется функция размещения, которой требуются входные аргументы конструктора. Это отправит транзакцию для размещения контракта. Чтобы дождаться получения транзакции, вы можете использовать метод deployed () транзакции размещения контракта.

Наконец, в терминале отображается адрес контракта.

Web3.py

В первой части скрипта экземпляр web3 (или провайдер) создается с помощью метода Web3 (Web3.HTTPProvider (provider_rpc)) с RPC провайдера. Изменяя RPC поставщика, вы можете выбрать, в какую сеть вы хотите отправить транзакцию.

Закрытый ключ и связанный с ним общедоступный адрес определяются для подписания транзакции и установления адреса отправителя.

Во втором разделе экземпляр контракта создается с помощью web3.eth.contract (), предоставляя ABI и байт-код, импортированные из файла компиляции. Затем транзакцию конструктора можно построить с помощью метода constructor (). BuildTransaction () контракта. Обратите внимание, что внутри конструктора () вам необходимо указать входные аргументы конструктора. Также необходимо указать исходную учетную запись. Обязательно используйте тот, который связан с закрытым ключом. Также количество транзакций можно получить с помощью метода web3.eth.getTransactionCount (address).

Транзакцию конструктора можно подписать с помощью web3.eth.account.signTransaction (), передав транзакцию и закрытый ключ.

Наконец, отправляется подписанная транзакция, адрес контракта отображается в терминале.

Чтение из смарт-контракта (методы вызова)

Методы вызова — это тип взаимодействия, который не изменяет хранилище контракта (изменяет переменные), то есть транзакцию отправлять не нужно.

Давайте рассмотрим файл get. * (Самый простой из них), который извлекает текущее значение, хранящееся в контракте. Вы можете найти фрагменты кода для каждой библиотеки здесь (они были произвольно названы get. *):

Для простоты, файл get состоит из двух разделов. В первом разделе («Определение поставщика и переменных») импортируются используемая библиотека и ABI контракта. Также определяется провайдер и адрес контракта. Обратите внимание, что providerRPC имеет как стандартную конечную точку RPC автономного узла, так и конечную точку для Moonbase Alpha.

Во втором разделе («Функция вызова») описывается фактический вызов контракта. Независимо от библиотеки создается экземпляр контракта (связанный с адресом контракта), из которого запрашивается метод вызова. Некоторые из основных выводов обсуждаются далее.

Web3.js

const Web3 = require('web3');
const { abi } = require('./compile');

/*
-- Define Provider & Variables --
*/
// Provider
const providerRPC = {
standalone: 'http://localhost:9933',
moonbase: 'https://rpc.testnet.moonbeam.network',
};
const web3 = new Web3(providerRPC.standalone); //Change to correct network

// Variables
const contractAddress = 'CONTRACT-ADDRESS-HERE';

/*
-- Call Function --
*/
// Create Contract Instance
const incrementer = new web3.eth.Contract(abi, contractAddress);

const get = async () => {
console.log(`Making a call to contract at address: ${contractAddress}`);

// Call Contract
const data = await incrementer.methods.number().call();

console.log(`The current number stored is: ${data}`);
};

get();

Ethers.js

const ethers = require('ethers');
const { abi } = require('./compile');

/*
-- Define Provider & Variables --
*/
// Provider
const providerRPC = {
standalone: {
name: 'moonbeam-standalone',
rpc: 'http://localhost:9933',
chainId: 1281,
},
moonbase: {
name: 'moonbase-alpha',
rpc: 'https://rpc.testnet.moonbeam.network',
chainId: 1287,
},
};
const provider = new ethers.providers.StaticJsonRpcProvider(
providerRPC.standalone.rpc,
{
chainId: providerRPC.standalone.chainId,
name: providerRPC.standalone.name,
}
); //Change to correct network

// Variables
const contractAddress = 'CONTRACT-ADDRESS-HERE';

/*
-- Call Function --
*/
// Create Contract Instance
const incrementer = new ethers.Contract(contractAddress, abi, provider);

const get = async () => {
console.log(`Making a call to contract at address: ${contractAddress}`);

// Call Contract
const data = await incrementer.number();

console.log(`The current number stored is: ${data}`);
};

get();

Web3.py

from compile import abi, bytecode
from web3 import Web3

#
# -- Define Provider & Variables --
#
# Provider
provider_rpc = {
'standalone': 'http://localhost:9933',
'alphanet': 'https://rpc.testnet.moonbeam.network',
}
web3 = Web3(Web3.HTTPProvider(provider_rpc["standalone"])) # Change to correct network

# Variables
contract_address = 'CONTRACT-ADDRESS-HERE'

#
# -- Call Function --
#
print(f'Making a call to contract at address: { contract_address }')

# Create Contract Instance
Incrementer = web3.eth.contract(address=contract_address, abi=abi)

# Call Contract
number = Incrementer.functions.number().call()

print(f'The current number stored is: { number } ')

Web3.js

В первой части скрипта (или провайдер) web3 создается с помощью конструктора Web3 с провайдером RPC. Изменяя RPC вы можете выбрать, в какую сеть вы хотите отправить транзакцию.

Закрытый ключ связанный с ним и общедоступный адрес определяются для подписания транзакции и ведения журнала. Требуется только закрытый ключ. Кроме того, байт-код и интерфейс контракта (ABI) извлекаются из экспорта компиляции.

Во втором разделе создается экземпляр контракта, предоставляя ABI. Затем используется функция размещения, которой требуются байт-код и аргументы функции-конструктора. Это генерирует boject транзакции.

После этого транзакцию можно подписать с помощью метода web3.eth.accounts.signTransaction (). Поле данные соответствуют байт-коду, а входные аргументы конструктора кодируются вместе. Обратите внимание, что значение газа получается с использованием опции EstimationGas () внутри транзакции конструктора.

Наконец, отправляется подписанная транзакция, адрес контракта отображается в терминале.

Ethers.js

В первой части сценария можно указать разные сети с помощью имени, URL-адреса RPC (обязательно) и идентификатора цепочки. Провайдер (аналогичный экземпляру web3) создается с помощью метода ethers.providers.StaticJsonRpcProvider. Альтернативой является использование метода ethers.providers.JsonRpcProvide (providerRPC), который требует только адрес конечной точки RPC поставщика. Но это могло создать проблемы совместимости с индивидуальными спецификациями проекта.

Закрытый ключ определяется для создания экземпляра кошелька, для которого также требуется поставщик из предыдущего шага. Экземпляр кошелька используется для подписи транзакций. Кроме того, байт-код и интерфейс контракта (ABI) извлекаются из экспорта компиляции.

Во втором разделе создается экземпляр контракта с помощью ethers.ContractFactory (), предоставляющий ABI, байт-код и кошелек. Таким образом, у экземпляра контракта уже есть подписывающая сторона. Затем используется функция размещения, которой требуются входные аргументы конструктора. Это отправит транзакцию для размещения контракта. Чтобы дождаться получения транзакции, вы можете использовать метод deployed () транзакции размещения контракта.

Наконец, в терминале отображается адрес контракта.

Web3.py

В первой части скрипта экземпляр web3 (или провайдер) создается с помощью метода Web3 (Web3.HTTPProvider (provider_rpc)) с RPC провайдера. Изменяя RPC поставщика, вы можете выбрать, в какую сеть вы хотите отправить транзакцию.

Закрытый ключ и связанный с ним общедоступный адрес определяются для подписания транзакции и установления адреса отправителя.

Во втором разделе экземпляр контракта создается с помощью web3.eth.contract (), предоставляя ABI и байт-код, импортированные из файла компиляции. Затем транзакцию конструктора можно построить с помощью метода constructor (). BuildTransaction () контракта. Обратите внимание, что внутри конструктора () вам необходимо указать входные аргументы конструктора. Также необходимо указать исходную учетную запись. Обязательно используйте тот, который связан с закрытым ключом. Также количество транзакций можно получить с помощью метода web3.eth.getTransactionCount (address).

Транзакцию конструктора можно подписать с помощью web3.eth.account.signTransaction (), передав транзакцию и закрытый ключ.

Наконец, отправляется подписанная транзакция, адрес контракта отображается в терминале.

Взаимодействие с смарт-контрактом (способы отправки)
Во-первых, давайте рассмотрим файл increment. *, Который увеличивает текущее число, хранящееся в контракте, на заданное значение. Здесь вы можете найти фрагменты кода для каждой библиотеки (они были произвольно названы increment. *):

Для простоты файл приращения состоит из двух разделов. В первом разделе («Определение поставщика и переменных») импортируются используемая библиотека и ABI контракта. Также определяются поставщик, адрес контракта и значение функции приращения. Обратите внимание, что providerRPC имеет как стандартную конечную точку RPC автономного узла, так и конечную точку для Moonbase Alpha.

Во втором разделе («Функция отправки») описывается фактическая функция, которая должна быть вызвана с транзакцией. Независимо от библиотеки создается экземпляр контракта (связанный с адресом контракта), из которого запрашивается функция, которая будет использоваться.

Web3.js

const Web3 = require('web3');
const { abi } = require('./compile');

/*
-- Define Provider & Variables --
*/
// Provider
const providerRPC = {
standalone: 'http://localhost:9933',
moonbase: 'https://rpc.testnet.moonbeam.network',
};
const web3 = new Web3(providerRPC.standalone); //Change to correct network

// Variables
const account_from = {
privateKey: 'YOUR-PRIVATE-KEY-HERE',
};
const contractAddress = 'CONTRACT-ADDRESS-HERE';
const _value = 3;

/*
-- Send Function --
*/
// Create Contract Instance
const incrementer = new web3.eth.Contract(abi, contractAddress);

// Build Increment Tx
const incrementTx = incrementer.methods.increment(_value);

const increment = async () => {
console.log(
`Calling the increment by ${_value} function in contract at address: ${contractAddress}`
);

// Sign Tx with PK
const createTransaction = await web3.eth.accounts.signTransaction(
{
to: contractAddress,
data: incrementTx.encodeABI(),
gas: await incrementTx.estimateGas(),
},
account_from.privateKey
);

// Send Tx and Wait for Receipt
const createReceipt = await web3.eth.sendSignedTransaction(
createTransaction.rawTransaction
);
console.log(`Tx successful with hash: ${createReceipt.transactionHash}`);
};

increment();

Ethers.js

const ethers = require('ethers');
const { abi } = require('./compile');

/*
-- Define Provider & Variables --
*/
// Provider
const providerRPC = {
standalone: {
name: 'moonbeam-standalone',
rpc: 'http://localhost:9933',
chainId: 1281,
},
moonbase: {
name: 'moonbase-alpha',
rpc: 'https://rpc.testnet.moonbeam.network',
chainId: 1287,
},
};
const provider = new ethers.providers.StaticJsonRpcProvider(
providerRPC.standalone.rpc,
{
chainId: providerRPC.standalone.chainId,
name: providerRPC.standalone.name,
}
); //Change to correct network

// Variables
const account_from = {
privateKey: 'YOUR-PRIVATE-KEY-HERE',
};
const contractAddress = 'CONTRACT-ADDRESS-HERE';
const _value = 3;

// Create Wallet
let wallet = new ethers.Wallet(account_from.privateKey, provider);

/*
-- Send Function --
*/
// Create Contract Instance with Signer
const incrementer = new ethers.Contract(contractAddress, abi, wallet);
const increment = async () => {
console.log(
`Calling the increment by ${_value} function in contract at address: ${contractAddress}`
);

// Sign-Send Tx and Wait for Receipt
const createReceipt = await incrementer.increment([_value]);
await createReceipt.wait();

console.log(`Tx successful with hash: ${createReceipt.hash}`);
};

increment();

Web3.py

from compile import abi, bytecode
from web3 import Web3

#
# -- Define Provider & Variables --
#
# Provider
provider_rpc = {
'standalone': 'http://localhost:9933',
'alphanet': 'https://rpc.testnet.moonbeam.network',
}
web3 = Web3(Web3.HTTPProvider(provider_rpc["standalone"])) # Change to correct network

# Variables
account_from = {
'private_key': 'YOUR-PRIVATE-KEY-HERE',
'address': 'PUBLIC-ADDRESS-OF-PK-HERE',
}
contract_address = 'CONTRACT-ADDRESS-HERE'
value = 3

#
# -- Send Function --
#
print(
f'Calling the increment by { value } function in contract at address: { contract_address }'
)

# Create Contract Instance
Incrementer = web3.eth.contract(address=contract_address, abi=abi)

# Build Increment Tx
increment_tx = Incrementer.functions.increment(value).buildTransaction(
{
'from': account_from['address'],
'nonce': web3.eth.getTransactionCount(account_from['address']),
}
)

# Sign Tx with PK
tx_create = web3.eth.account.signTransaction(increment_tx, account_from['private_key'])

# Send Tx and Wait for Receipt
tx_hash = web3.eth.sendRawTransaction(tx_create.rawTransaction)
tx_receipt = web3.eth.waitForTransactionReceipt(tx_hash)

print(f'Tx successful with hash: { tx_receipt.transactionHash.hex() }')

Второй файл, который взаимодействует с контрактом, — это файл reset. *, Который сбрасывает число, хранящееся в контракте, на ноль. Вы можете найти фрагменты кода для каждой библиотеки здесь (они были произвольно названы reset. *):

Структура каждого файла очень похожа на его аналог инкремента. * Для каждой библиотеки. Основное отличие — это вызываемый метод.

Web3.js

const Web3 = require('web3');
const { abi } = require('./compile');

/*
-- Define Provider & Variables --
*/
// Provider
const providerRPC = {
standalone: 'http://localhost:9933',
moonbase: 'https://rpc.testnet.moonbeam.network',
};
const web3 = new Web3(providerRPC.standalone); //Change to correct network

// Variables
const account_from = {
privateKey: 'YOUR-PRIVATE-KEY-HERE',
};
const contractAddress = 'CONTRACT-ADDRESS-HERE';

/*
-- Send Function --
*/
// Create Contract Instance
const incrementer = new web3.eth.Contract(abi, contractAddress);

// Build Reset Tx
const resetTx = incrementer.methods.reset();

const reset = async () => {
console.log(
`Calling the reset function in contract at address: ${contractAddress}`
);

// Sign Tx with PK
const createTransaction = await web3.eth.accounts.signTransaction(
{
to: contractAddress,
data: resetTx.encodeABI(),
gas: await resetTx.estimateGas(),
},
account_from.privateKey
);

// Send Tx and Wait for Receipt
const createReceipt = await web3.eth.sendSignedTransaction(
createTransaction.rawTransaction
);
console.log(`Tx successful with hash: ${createReceipt.transactionHash}`);
};

reset()

Ethers.js

const ethers = require('ethers');
const { abi } = require('./compile');

/*
-- Define Provider & Variables --
*/
// Provider
const providerRPC = {
standalone: {
name: 'moonbeam-standalone',
rpc: 'http://localhost:9933',
chainId: 1281,
},
moonbase: {
name: 'moonbase-alpha',
rpc: 'https://rpc.testnet.moonbeam.network',
chainId: 1287,
},
};
const provider = new ethers.providers.StaticJsonRpcProvider(
providerRPC.standalone.rpc,
{
chainId: providerRPC.standalone.chainId,
name: providerRPC.standalone.name,
}
); //Change to correct network

// Variables
const account_from = {
privateKey: 'YOUR-PRIVATE-KEY-HERE',
};
const contractAddress = 'CONTRACT-ADDRESS-HERE';

// Create Wallet
let wallet = new ethers.Wallet(account_from.privateKey, provider);

/*
-- Send Function --
*/
// Create Contract Instance with Signer
const incrementer = new ethers.Contract(contractAddress, abi, wallet);
const reset = async () => {
console.log(
`Calling the reset function in contract at address: ${contractAddress}`
);

// Sign-Send Tx and Wait for Receipt
const createReceipt = await incrementer.reset();
await createReceipt.wait();

console.log(`Tx successful with hash: ${createReceipt.hash}`);
};

reset();

Web3.py

from compile import abi, bytecode
from web3 import Web3

#
# -- Define Provider & Variables --
#
# Provider
provider_rpc = {
'standalone': 'http://localhost:9933',
'alphanet': 'https://rpc.testnet.moonbeam.network',
}
web3 = Web3(Web3.HTTPProvider(provider_rpc["standalone"])) # Change to correct network

# Variables
account_from = {
'private_key': 'YOUR-PRIVATE-KEY-HERE',
'address': 'PUBLIC-ADDRESS-OF-PK-HERE',
}
contract_address = 'CONTRACT-ADDRESS-HERE'

#
# -- Call Function --
#
print(f'Calling the reset function in contract at address: { contract_address }')

# Create Contract Instance
Incrementer = web3.eth.contract(address=contract_address, abi=abi)

# Build Reset Tx
reset_tx = Incrementer.functions.reset().buildTransaction(
{
'from': account_from['address'],
'nonce': web3.eth.getTransactionCount(account_from['address']),
}
)

# Sign Tx with PK
tx_create = web3.eth.account.signTransaction(reset_tx, account_from['private_key'])

# Send Tx and Wait for Receipt
tx_hash = web3.eth.sendRawTransaction(tx_create.rawTransaction)
tx_receipt = web3.eth.waitForTransactionReceipt(tx_hash)

print(f'Tx successful with hash: { tx_receipt.transactionHash.hex() }')

Web3.js

В первой части сценария (increment или reset) экземпляр web3 (или поставщик) создается с помощью конструктора Web3 с поставщиком RPC. Изменяя RPC поставщика, предоставленный конструктору, Вы можете выбрать, в какую сеть Вы хотите отправить транзакцию.

Закрытый ключ и связанный с ним общедоступный адрес определяются для подписания транзакции и ведения журнала. Требуется только закрытый ключ. Кроме того, для взаимодействия с ним необходимы интерфейс контракта (ABI) и адрес. При необходимости вы можете определить любую переменную, необходимую в качестве входных данных для функции, с которой вы собираетесь взаимодействовать.

Во втором разделе экземпляр контракта создается с помощью web3.eth.Contract (), предоставляя ABI и адрес. Затем вы можете создать объект транзакции с помощью функции contract.methods.methodName (_input), заменив контракт, methodName и _input экземпляром контракта, функцией для вызова и вводом функции (при необходимости).

После этого транзакцию можно подписать с помощью метода web3.eth.accounts.signTransaction (). Поле данных соответствует объекту транзакции из предыдущего шага. Обратите внимание на то, что стоимость газа получается с помощью опции EstimateGas () внутри объекта транзакции.

Наконец, отправляется подписанная транзакция, и хеш транзакции отображается в терминале.

Ethers.js

В первой части сценария (increment или reset) можно указать разные сети с помощью имени, URL-адреса RPC (обязательно) и идентификатора цепочки. Провайдер (аналогичный экземпляру web3) создается с помощью метода ethers.providers.StaticJsonRpcProvider. Альтернативой является использование метода ethers.providers.JsonRpcProvide (providerRPC), для которого требуется только адрес конечной точки RPC поставщика. Но это могло создать проблемы совместимости с индивидуальными спецификациями проекта.

Закрытый ключ определяется для создания экземпляра кошелька, для которого также требуется поставщик из предыдущего шага. Экземпляр кошелька используется для подписи транзакций. Кроме того, для взаимодействия с ним необходимы интерфейс контракта (ABI) и адрес. При необходимости вы можете определить любую переменную, необходимую в качестве входных данных для функции, с которой вы собираетесь взаимодействовать.

Во втором разделе создается экземпляр контракта с помощью ethers.Contract () с указанием его адреса, ABI и кошелька. Таким образом, у экземпляра контракта уже есть подписывающая сторона. Затем транзакция, соответствующая конкретной функции, может быть отправлена ​​с помощью функции contract.methodName (_input), заменяя контракт, methodName и _input экземпляром контракта, функцией для вызова и вводом функции (при необходимости). Чтобы дождаться получения транзакции, вы можете использовать метод wait () транзакции размещения контракта.

Наконец, в терминале отображается хеш транзакции.

Web3.py

В первой части сценария ((increment или reset) экземпляр web3 (или поставщик) создается с использованием метода Web3 (Web3.HTTPProvider (provider_rpc)) с RPC поставщика. Изменяя RPC поставщика, вы можете выбрать, в какую сеть вы хотите отправить транзакцию.

Закрытый ключ и связанный с ним общедоступный адрес определяются для подписания транзакции и установления адреса отправителя. Кроме того, для взаимодействия с ним необходимы интерфейс контракта (ABI) и адрес.

Во втором разделе экземпляр контракта создается с помощью web3.eth.contract (), предоставляя ABI и адрес. Затем вы можете создать объект транзакции с помощью функции contract.functions.methodName (_input) .buildTransaction, заменив контракт, methodName и _input экземпляром контракта, функцией для вызова и вводом функции (при необходимости). Внутри buildTransaction () необходимо указать учетную запись from. Обязательно используйте тот, который связан с закрытым ключом. Также количество транзакций можно получить с помощью метода web3.eth.getTransactionCount (address).

Транзакцию можно подписать с помощью web3.eth.account.signTransaction (), передав объект транзакции предыдущего шага и закрытый ключ.

Наконец, в терминале отображается хеш транзакции.

Запуск скриптов

В этом разделе показанный ранее код был адаптирован для работы с автономным узлом, который вы можете запустить, следуя этому руководству. Кроме того, каждая транзакция была отправлена с предварительно пополненной учетной записи, которая поставляется с узлом:

  • Private key: 99B3C12287537E38C90A9219D4CB074A89A16E9CDB20BF85728EBD97C343E342
  • Public address: 0x6Be02d1d3665660d22FF9624b7BE0551ee1Ac91b

Сначала разместите контракт, запустив (обратите внимание, что каталог был переименован для каждой библиотеки):

Это разместит контракт и вернет адрес:

Затем запустите файл increment. Вы можете использовать файл get для проверки значения числа, хранящегося в контракте, до и после его увеличения:

Это отобразит значение до транзакции increment, хэш транзакции и значение после:

Наконец, запустите файл сброса. Еще раз, вы можете использовать файл get для проверки значения числа, хранящегося в контракте, до и после его сброса:

Обратная связь

Это простой пример, но он дает контекст того, как Вы можете начать работать с Moonbeam и опробовать его функции совместимости с Ethereum. Нам интересно узнать о Вашем опыте выполнения шагов, описанных в этом руководстве, или о Вашем опыте использования других инструментов на основе Ethereum с Moonbeam. Присоединяйтесь к нам в Discord Moonbeam. Мы будем рады услышать Ваши отзывы о Moonbeam и ответить на любые Ваши вопросы.

Подготовлено при участии GameOver#9212, Lyn.

--

--

Moonbeam in Russian
Moonbeam in Russian

Written by Moonbeam in Russian

Moonbeam — это совместимая с Ethereum платформа смарт-контрактов на Polkadot

No responses yet