Your contracts must be inherited from a standard contract interface called "BaseRelayRecipient.sol".
By implementing this interface, your smart contracts will be able to interact with the LACNet Gas Model, facilitating the transaction relay and enables clients to send transactions to the blockchain without incurring any fees.
Adapt your Smart Contract to our GAS Distribution Protocol
As the sender with which the transactions arrive at the receipient contract is the address of the RelayHub contract, a mechanism is necessary to obtain the original sender of the client or user who sent the transaction.
To make this possible, we take advantage of the atomicity of the execution of the transactions in the EVM. That is, every time a transaction is sent to the RelayHub, the address of the original sender is stored, which is then retrieved by making a call to the RelayHub from the recipient contract.
This function to obtain the original sender is located in an abstract contract, which has to be inherited by all the contracts that will be deployed in the network.
The abstract contract to inherit is BaseRelayRecipient. After inherit this contract you have to update the value of the internal variable trustedForwarder by one of following address.
On Open-protestnet = 0xa4B5eE2906090ce2cDbf5dfff944db26f397037D
On Mainnet = 0xEAA5420AF59305c5ecacCB38fcDe70198001d147
BaseRelayRecipient.sol
// 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;
}
}
}
Because the transaction is relayed by other account different from the original message sender, you need to pay attention on the interaction of you contract that involves a "msg.sender" it's need to be replaces by "_msgSender()" function
pragma solidity >=0.5.0 <0.7.0;
import "./BaseRelayRecipient.sol";
/**
* @title Storage
* @dev Store & retreive value in a variable
*/
contract Storage is BaseRelayRecipient{
uint256 number;
address owner;
constructor() public {
owner = _msgSender(); //instead of msg.Sender
}
/**
* @dev Store value in variable
* @param num value to store
*/
function store(uint256 num) public {
number = num;
emit ValueSeted(_msgSender(),num); //instead of msg.Sender
}
/**
* @dev Return value
* @return value of 'number'
*/
function retreive() public view returns (uint256){
return number;
}
function getOwner() public view returns (address){
return owner;
}
event ValueSeted(address sender, uint256 value);
}