What is the use of Uniswap Router Initialization in a Token Contract - ethereum

I just started on building Tokens using ETH & BSC, this is one statement which I see in many Contracts.
Inside the Constructor method, the Uniswap router is iniliazed probably with the V2 version. What is the use of this?
constructor () public {
_rOwned[_msgSender()] = _rTotal;
IUniswapV2Router02 _uniswapV2Router = IUniswapV2Router02(0x10ED43C718714eb63d5aA57B78B54704E256024E);
// Create a uniswap pair for this new token
uniswapV2Pair = IUniswapV2Factory(_uniswapV2Router.factory())
.createPair(address(this), _uniswapV2Router.WETH());
// set the rest of the contract variables
uniswapV2Router = _uniswapV2Router;
Why is this initialization required? What is the functionality of this?
Appreciate if someone could help.
Thanks

IUniswapV2Router02 _uniswapV2Router = IUniswapV2Router02(0x10ED43C718714eb63d5aA57B78B54704E256024E);
This line initializes a pointer to the 0x10ED... address and expects the contract (deployed at the 0x10ED... address) to implement the IUniswapV2Router02 interface.
The interface is defined somewhere with the caller contract source code.
It allows you to execute and call functions defined by the interface instead of building low-level calls. It also allows you to use the returned datatypes instead of parsing the returned binary.
Example:
pragma solidity ^0.8.5;
interface IRemote {
function foo() external view returns (bool);
}
contract MyContract {
IRemote remote;
constructor() {
remote = IRemote(address(0x123));
}
function getFoo() external view returns (bool) {
bool returnedValue = remote.foo();
return returnedValue;
}
}

Related

Solidity 0.5.1, when creating a contract object, why do we have to pass the token to that contract's constructor even if there is no constructor

Here is the code:
pragma solidity 0.5.1;
contract ERC20Token{
string public name;
mapping(address => uint256) public balances;
function mint() public{
balances[tx.origin] += 1;
}
}
contract MyContract {
address payable wallet;
address public token;
constructor(address payable _wallet, address _token) public {
wallet = _wallet;
token = _token;
}
function() external payable {
buyToken();
}
function buyToken() public payable{
ERC20Token _token = ERC20Token(address(token));
_token.mint();
wallet.transfer(msg.value);
}
}
Process:
First, we are getting the ERC20Token contract address by deploying the ERC20Token contract in the first place.
Secondly, MyContract constructor takes (a wallet address and the ERC20Token contract address) as two parameters.
Then, we create a ERC20Token contract object from this line
ERC20Token _token = ERC20Token(address(token));
I got confused by how this line worked. Even the ERC20Token contract does not contain any constructor, where the above code passes the token as a parameter to the ERC20Token constructor.
If i delete the token parameter from the above code:
ERC20Token _token = ERC20Token();
I will get an error called
Exactly one argument expected for explicit type conversion
Could anyone explain to me why this happens in solidity?
Without the new keyword, you're making a pointer to an already deployed instance of the ERC20Token contract, passing its address in the argument. Since the contract is already deployed and the constructor has been already executed, you do not pass its constructor params.
// address of existing instance
ERC20Token _token = ERC20Token(address(token));
With the new keyword, you'd be deploying a new instance of ERC20Token, specifying its constructor params. Its address is then available by typecasting the variable to address type.
// creating new instance
// passing constructor params (in your case empty)
ERC20Token _token = new ERC20Token();
// address of the newly deployed contract
address tokenAddress = address(_token);

Issues using a delegateCall (proxy contract with Solidity) and using variables inside the delegate contract

I've written a simple proxy contract with solidity and I've got an issue with the variables inside the delegate contract. When I delegateCall, all my variables are equal to 0, except if there are constant. Is there any reason for that or am I missing something ?
My proxy contract :
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.3;
contract Proxy {
mapping(string => address) public strategies;
function addStrategy(string memory id, address implementation) external {
strategies[id] = implementation;
}
function removeStrategy(string memory id) external {
delete strategies[id];
}
function displayVar(string memory strategyId) external {
address strategy = strategies[strategyId];
require(strategy != address(0x0), "Strategy not found..");
(bool success, bytes memory data) = strategy.delegatecall(
abi.encodeWithSignature("displayVar()")
);
}
}
The deleguate contract :
pragma solidity ^0.8.3;
import "hardhat/console.sol";
contract Delegate {
mapping(string => address) public strategies;
address public constant CRV = 0xD533a949740bb3306d119CC777fa900bA034cd52;
address public curve = 0x90E00ACe148ca3b23Ac1bC8C240C2a7Dd9c2d7f5;
address public constant cvx = 0xF403C135812408BFbE8713b5A23a04b3D48AAE31;
address public constant CVX = 0x4e3FBD56CD56c3e72c1403e103b45Db9da5B9D2B;
function displayVar() external returns (bool) {
console.log(CRV);
console.log(curve);
console.log(cvx);
console.log(CVX);
}
}
the test with HardHat :
import { Contract, ContractFactory } from "ethers";
import { ethers } from "hardhat";
describe("test via proxy", function () {
let Proxy: ContractFactory, proxy: Contract;
let Delegate: ContractFactory, delegate: Contract;
const stratName = "test";
before(async function () {
Proxy = await ethers.getContractFactory("Proxy");
proxy = await Proxy.deploy();
await proxy.deployed();
Delegate = await ethers.getContractFactory("Delegate");
delegate = await Delegate.deploy();
await delegate.deployed();
await proxy.addStrategy(stratName, delegate.address);
});
it("should display", async function () {
const [owner] = await ethers.getSigners();
await proxy.connect(owner).displayVar(stratName);
});
});
And finally the output is :
0xd533a949740bb3306d119cc777fa900ba034cd52
0x0000000000000000000000000000000000000000
0xf403c135812408bfbe8713b5a23a04b3d48aae31
0x4e3fbd56cd56c3e72c1403e103b45db9da5b9d2b
A quick intro:
When you use delegatecall, you are “using” the targeted contract’s code (in your case Delegate) but keeping the storage of the proxy. In other words, the storage of the proxy is completely independent (that is the purpose of the proxy, to be upgradable and / or to save gas on deployment.
With this in mind, your proxy contract can only use the code of delegate, but maintaining its own storage. But, constant and immutable variables do not occupy a storage slot, they are injected in the bytecode at compile time. That is why your proxy also has them. But all the other variables are defaulted to 0 (depending on the type).
The point of using Proxy contract is to keep the state of different implementation versions in the same contract via the delegatecall. Therefore using constructor is not a safe method inside the implementation contract because its state inside the constuctor is set inside the implementation contract when we deploy the contract: Solidity: Why use Initialize function instead of constructor?
Initializing storage variables is not safe either because those state variables are set inside the implementation contract when we deploy them like the constructor.
// this is not safe
// you should move the assignment inside an initializer function
// this is not set inside the proxy
address public curve = 0x90E00ACe148ca3b23Ac1bC8C240C2a7Dd9c2d7f5;
However, if you have constant and immutable variables, those variables will be inside the bytecode of your contract and your proxy needs those variable, it will point to bytecode and get the code. Using constant and immutable is believed to be safe in this case. However, if you set those variables in V1 and then over time you upgraded to V2,V3 etc. If your V1 had selfdestruct function and you killed the contract in the future, V1's bytecode will be deleted and therefore your proxy will no longer have access to those variables.

Solidity: which method should I use to call a function of an external Contract?

When using solidity, I have a doubt when I need to call a function which was created in a different contract. I know 2 ways of doing it, and I don't understand what is more recommendable and why. These are the ways I know:
Method 1:
contract A {
function foo() external {
return true;
}
}
contract B is A {
foo();
}
Method 2:
contract A {
function foo() external {
return true;
}
}
contract B {
function callFoo() external {
A a = A(addressA);
return a.foo();
}
}
Could anyone tell me the differences, and when it is more convenient wo user wither Method 1 or Method 2?
Thank you!!
Method 1 is used when you're calling a contract that is deployed on the same address. It can be either a parent of your Contract B or a library that your contract has imported.
Since the foo method is external, you'd need to call it using this.foo();.
An external function f cannot be called internally (i.e. f() does not work, but this.f() works).
Source: Solidity docs
If it were public, you could call it internally, just using foo().
Method 2 is used when you're calling a contract that is deployed on a different address.
Your Contract B than doesn't have to redefine the Contract A, and can only define the interface:
// this is just an interface of an external contract
interface A {
function foo() external returns (bool);
}
// this is your contract
contract B {
function callFoo() external returns (bool) {
A a = A(addressA);
return a.foo();
}
}

Solidity function implementing `public onlyOwner` cannot be called even by the owner

I am following along the documentation here: https://docs.alchemyapi.io/alchemy/tutorials/how-to-create-an-nft/how-to-mint-a-nft. And have a smart contract of form:
pragma solidity ^0.8.0;
import "#openzeppelin/contracts/token/ERC721/ERC721.sol";
import "#openzeppelin/contracts/utils/Counters.sol";
import "#openzeppelin/contracts/access/Ownable.sol";
contract NFTA is ERC721, Ownable {
using Counters for Counters.Counter;
Counters.Counter public _tokenIds;
mapping (uint256 => string) public _tokenURIs;
mapping(string => uint8) public hashes;
constructor() public ERC721("NFTA", "NFT") {}
function mintNFT(address recipient, string memory tokenURI)
public onlyOwner
returns (uint256)
{
_tokenIds.increment();
uint256 newItemId = _tokenIds.current();
_mint(recipient, newItemId);
_setTokenURI(newItemId, tokenURI);
return newItemId;
}
/**
* #dev Sets `_tokenURI` as the tokenURI of `tokenId`.
*
* Requirements:
*
* - `tokenId` must exist.
*/
function _setTokenURI(uint256 tokenId, string memory _tokenURI) internal virtual {
require(_exists(tokenId), "ERC721URIStorage: URI set of nonexistent token");
_tokenURIs[tokenId] = _tokenURI;
}
}
When I attempt to estimate the gas cost of minting with this:
const MY_PUBLIC_KEY = '..'
const MY_PRIVATE_KEY = '..'
const ALCHEMY = {
http: '',
websocket:'',
}
const { createAlchemyWeb3 } = require("#alch/alchemy-web3");
const web3 = createAlchemyWeb3(ALCHEMY.http);
const NFTA = require("../artifacts/contracts/OpenSea.sol/NFTA.json");
const address_a = '0x...';
const nft_A = new web3.eth.Contract(NFTA.abi, address_a);
async function mint({ tokenURI, run }){
const nonce = await web3.eth.getTransactionCount(MY_PUBLIC_KEY, 'latest');
const fn = nft_A.methods.mintNFT(MY_PUBLIC_KEY, '')
console.log( 'fn: ', fn.estimateGas() )
}
mint({ tokenURI: '', run: true })
I receive error:
(node:29262) UnhandledPromiseRejectionWarning: Error: Returned error: execution reverted: Ownable: caller is not the owner
Presumably because mintNFT is public onlyOwner. However, when I check Etherscan, the From field is the same as MY_PUBLIC_KEY, and I'm not sure what else can be done to sign the transaction as from MY_PUBLIC_KEY. The easy way to solve this is to remove the onlyOwner from function mintNFT, and everything runs as expected. But suppose we want to keep onlyOwner, how would I sign the transaction beyond what is already written above.
Note I'm using hardHat to compile the contracts and deploying them. That is:
npx hardhat compile
npx hardhat run scripts/deploy.js
=============================================
addendum
The exact code given by alchemy to deploy the mint is:
async function mintNFT(tokenURI) {
const nonce = await web3.eth.getTransactionCount(PUBLIC_KEY, 'latest'); //get latest nonce
//the transaction
const tx = {
'from': PUBLIC_KEY,
'to': contractAddress,
'nonce': nonce,
'gas': 500000,
'data': nftContract.methods.mintNFT(PUBLIC_KEY, tokenURI).encodeABI()
};
Note in the transaction the from field is PUBLIC_KEY, the same PUBLIC_KEY that deployed the contract, and in this case the nftContract has public onlyOwner specified. This is exactly what I have done. So conceptually who owns this NFT code? On etherscan is it the to address ( the contract address ), or the from address, which is my public key, the address that deployed the contract, and the one that is calling mint, which is now failing with caller is not the owner error.
Search the internet, I see others have encountered this problem here: https://ethereum.stackexchange.com/questions/94114/erc721-testing-transferfrom, for Truffle you can specify the caller with extra field:
await nft.transferFrom(accounts[0], accounts[1], 1, { from: accounts[1] })
Extra parameters is not an option here because I'm using hardhat.
OpenZeppelin's Ownable.sol defines the default owner value as the contract deployer. You can later change it by calling transferOwnership() or renounce the owner (i.e. set to 0x0) by calling renounceOwnership().
The onlyOwner modifier reverts the transaction if it's not sent by the current owner. (see the code)
So you need to call the mintNFT() function from the same address that deployed the contract, because that's the current owner. Or you can change the owner first by calling transferOwnership() (from the current owner address).
Removing the onlyOwner modifier from the mintNFT() function would allow anyone to call the function.
Answering this for anyone else who stumbles across the issue while using the Alchemy tutorial:
In the tutorial, it says to init the contract in your mint method like this:
const contract = require("../artifacts/contracts/MyNFT.sol/MyNFT.json");
const contractAddress = "0x81c587EB0fE773404c42c1d2666b5f557C470eED";
const nftContract = new web3.eth.Contract(contract.abi, contractAddress);
However, if you attempt to call estimateGas() or encodeABI() it will fail with the onlyOwner error.
The solution is to change the third line to:
const nftContract = new web3.eth.Contract(contract.abi, contractAddress, {
from: PUBLIC_KEY
});
This will set a default value of "From" so that when you call estimateGas() on a mint function marked onlyOwner, it will be able to use that from field to see that its the owner calling the estimateGas.
Took forever to figure this out.
I finally figured it out, the contract does not initialize the way I deploy it. So you have to initialize it after deployment.

How to get keccak256 hash in Solidity

I just got started with solidity, I have used truffle to compile and deploy the code to ganache, everything works as I expect, I can call the other functions in the code, but there are certain functions that only the owner can access, the code appears to use keccak256 to get back the address calling the function and determine if the caller address is allowed, I have tried to hash my eth address using this website:
https://emn178.github.io/online-tools/keccak_256.html
and then add the hash to the code before recompiling again, but calling the owner function still throws this error:
"Error: VM Exception while processing transaction: revert"
What am i doing wrong ?
Here's the code with the original hash.
modifier onlyOwner(){
address _customerAddress = msg.sender;
require(owners[keccak256(_customerAddress)]);
_;
}
// owners list
mapping(bytes32 => bool) public owners;
function PetShop()
public
{
// add owners here
owners[0x66e62cf7a807daaf3e42f7af3befe7b2416a79ba5348820245a69fe701f80eb4] = true;
}
/*---------- Owner ONLY FUNCTIONS ----------*/
function disableDogs()
onlyOwner()
public
{
onlyDogs = false;
}
/*-----replace owner ------*/
function setOwner(bytes32 _identifier, bool _status)
onlyOwner()
public
{
owners[_identifier] = _status;
}
/*-----set price for pet adoption----*/
function setAdoptionRequirement(uint256 _amountOfTokens)
onlyOwner()
public
{
AdoptionRequirement = _amountOfTokens;
}
The keccak256 implementation in Solidity stores data differently.
keccak256(...) returns (bytes32):
compute the Ethereum-SHA-3 (Keccak-256) hash of the (tightly packed) arguments
Just use the function yourself when creating the contract:
function PetShop() public {
// add owners here
owners[keccak256(msg.sender)] = true;
}
as of now
// .encodePacked merges inputs together
owners[keccak256(abi.encodePacked(_text, _num, _addr))}=true
abi.encodePacked() , Solidity supports a non-standard packed mode where:
types shorter than 32 bytes are neither zero padded nor sign extended
dynamic types are encoded in-place and without the length.
array elements are padded, but still encoded in-place