Because LNet is using two extra parameters on the transaction ("NodeAddres" and "ExpirationDate") you need to implement your signer to add this parametes or use one of ower signers wich adds this parameters on the transaction as the model requires.
Install Node https://nodejs.org/en/download/package-manager/all
Create a directory
mkdir my_project
cd my_project
Install Dependencies
npm init
npm install @lacchain/gas-model-provider
npm install ethers
npm install --save-dev [email protected]
Initialize Hardhat
npx hardhat init
You will get...
888 888 888 888 888 888 888 888 888 888 888 888 888 888 888 8888888888 8888b. 888d888 .d88888 88888b. 8888b. 888888 888 888 "88b 888P" d88" 888 888 "88b "88b 888 888 888 .d888888 888 888 888 888 888 .d888888 888 888 888 888 888 888 Y88b 888 888 888 888 888 Y88b. 888 888 "Y888888 888 "Y88888 888 888 "Y888888 "Y888 |
Move to contracts directory
cd contracts
$ my_project/contracts
Create a file with the "BaseRelayRecipient.sol" contract
✔ Remember all the contracts in LNet requires to implement BaseRelayRecipient contract to allow relaying transaction on the gas model.
✔ Check lines 13 and 14 and uncomment trustedForwarder address to set open-protestnet or mainet
✔ We are using open-protestnet on this documentation
// SPDX-License-Identifier:MIT
pragma solidity >=0.8.0 <0.9.0;
/**
* A base contract to be inherited by any contract that want to receive relayed transactions
* A subclass must use "_msgSender()" instead of "msg.sender"
*/
abstract contract BaseRelayRecipient{
/*
* Forwarder singleton we accept calls from
*/
address internal trustedForwarder = 0xa4B5eE2906090ce2cDbf5dfff944db26f397037D; //open-protestnet
//address internal trustedForwarder = 0xEAA5420AF59305c5ecacCB38fcDe70198001d147; //mainnet
/**
* return the sender of this call.
* if the call came through our Relay Hub, return the original sender.
* should be used in the contract anywhere instead of msg.sender
*/
function _msgSender() internal virtual returns (address sender) {
bytes memory bytesRelayHub;
(,bytesRelayHub) = trustedForwarder.call(abi.encodeWithSignature("getRelayHub()"));
if (msg.sender == abi.decode(bytesRelayHub, (address))){ //sender is RelayHub then return origin sender
bytes memory bytesSender;
(,bytesSender) = trustedForwarder.call(abi.encodeWithSignature("getMsgSender()"));
return abi.decode(bytesSender, (address));
} else { //sender is not RelayHub, so it is another smart contract
return msg.sender;
}
}
}
Create a file for the "Greeter.sol" contract
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.24;
import './BaseRelayRecipient.sol';
contract Greeter is BaseRelayRecipient {
address public owner;
string public greeting = "Hello ";
constructor() {
owner = _msgSender();
}
function greetMe(string memory _name) public view returns (string memory) {
return string(abi.encodePacked(greeting, _name));
}
function getOwner() public view returns(address){
return owner;
}
}
Compile the contracts
npx hardhat compile
Compiled 2 Solidity files successfully (evm target: paris).
cd ..
mkdir scripts
cd scripts
$ my_project
$ my_project/scripts
Create a deployGreeter.js file
EDIT THE FILE:
✔ Uncomment the network you need to work... in this example TESTNET
✔ If you have not a node please refeer to: Testnet-Node
✔ {{YOUR_RPC_IP_OR_URL}} replace with the rpc information from your node
✔ {{ YOUR_NODE_ADDRESS }} replace with the public address from your node
✔ {{ YOUR_PRIVATE_KEY }} replace with your private key, comments below describe how to creat your private key.
HOW TO CREATE YOUR OWN PRIVATE KEY:
Crete a file genkey.cjs:var ethers = require('ethers'); var crypto = require('crypto');` var id = crypto.randomBytes(32).toString('hex'); var privateKey = "0x"+id; console.log("SAVE BUT DO NOT SHARE THIS:", privateKey); var wallet = new ethers.Wallet(privateKey); console.log("Address: " + wallet.address);node genkey.cjs
const { ethers } = require("ethers");
const { LacchainProvider, LacchainSigner } = require('@lacchain/gas-model-provider');
const contractAbi = require("../artifacts/contracts/Greeter.sol/Greeter.json");
async function main() {
//LOCAL
//const yourRPCNode = "{{YOUR_RPC_IP_OR_URL}}";
//const nodeAddress = "{{YOUR_NODE_ADDRESS}}";
//TESTNET
const yourRPCNode = "{{YOUR_RPC_IP_OR_URL}}";
const nodeAddress = "{{YOUR_NODE_ADDRESS}}";
//MAINNET
//const yourRPCNode = "{{YOUR_RPC_IP_OR_URL}}";
//const nodeAddress = "{{YOUR_NODE_ADDRESS}}";
//Contract Owner
const privateKey = "{{YOUR_PRIVATE_KEY}}";
console.log("Starting deploy of contract: ", contractAbi.contractName);
// current date and time + 5 miutes
const now = new Date();
const expiration_date = now.getTime() + (5 * 60 * 1000);
const provider = new LacchainProvider(yourRPCNode);
const signer = new LacchainSigner(
privateKey,
provider,
nodeAddress,
expiration_date
);
console.log(`Create Factory ${contractAbi.contractName}...`);
const contractFactory = new ethers.ContractFactory(
contractAbi.abi,
contractAbi.bytecode,
signer
);
console.log(`Deploying ${contractAbi.contractName}...`);
const contract = await contractFactory.deploy();
const receipt = await contract.deploymentTransaction()?.wait();
console.log("Contract deployed!");
const contractAddress = receipt?.contractAddress;
console.log(`${contractAbi.contractName} Contract Address: `, contractAddress );
deployedContract = new ethers.Contract(contractAddress, contractAbi.abi, provider);
deployedContractOwner = await deployedContract.getOwner();
console.log(`${contractAbi.contractName} Owner Address: `,deployedContractOwner)
geetResponse = await deployedContract.greetMe('Alice');
console.log(`${contractAbi.contractName} greetMe('Alice'): `,geetResponse)
}
main().catch(error => {
console.error(error);
process.exitCode = 1;
});
Move to root directory
cd ..
$ my_project
Deploy Contract
npx hardhat run scripts/deployGreeter.js
Starting deploy of contract: Greeter
Create Factory Greeter...
Deploying Greeter...
Contract deployed!
Greeter Contract Address: 0x291a64e358A14686c38E7CA5703ea40207Dd0b7B
Greeter Owner Address: 0x248906Bf539e8f16FbD14c001f7Bd3D712f95D3E
Greeter greetMe('Alice'): Hello Alice
Create a deployGreeter.js file
EDIT THE FILE:
✔ Uncomment the network you need to work... in this example TESTNET
✔ If you have not a node please refeer to: Testnet-Node
✔ {{YOUR_RPC_IP_OR_URL}} replace with the rpc information from your node
✔ {{ YOUR_NODE_ADDRESS }} replace with the public address from your node
✔ {{ YOUR_PRIVATE_KEY }} replace with your private key, comments below describe how to creat your private key.
HOW TO CREATE YOUR OWN PRIVATE KEY:
var crypto = require('crypto');` var id = crypto.randomBytes(32).toString('hex'); var privateKey = "0x"+id; console.log("SAVE BUT DO NOT SHARE THIS:", privateKey); var wallet = new ethers.Wallet(privateKey); console.log("Address: " + wallet.address);
//
//
Deploy Contract
npx hardhat run scripts/deployGreeter.js
Starting deploy of contract: Greeter
Create Factory Greeter...
Deploying Greeter...
Contract deployed!
Greeter Contract Address: 0x291a64e358A14686c38E7CA5703ea40207Dd0b7B
Greeter Owner Address: 0x248906Bf539e8f16FbD14c001f7Bd3D712f95D3E
Greeter greetMe('Alice'): Hello Alice