How to make a Factory Contract which deploys a UUPS Proxy? - blockchain

I have UUPS erc721 contract. I have deployed them. Now I have a proxy contract and a logic contract.
Lets say logic contract has address 0x1234
I want a factory contract to deploy multiple upgradeable proxies by copying a already deployed proxy from blockchain and all those proxies using logic contract at address 0x1234.
I want the project to be like as shown in the figure.
I have tried the following code but it does not produce the expected result. Proxy is not initialized/Deployed :
My ERC721 contract takes ownerAddress, name and symbol as initializer arguments. ERC721 is upgradeable so it uses a initializer and not a constructor.
pragma solidity 0.8.15;
import "./GenericERC721.sol";
import "./cloneFactory.sol";
import "#openzeppelin/contracts/access/Ownable.sol";
import "#openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol";
contract GenericFactory is Ownable, CloneFactory {
address public proxyAddress;
address public logicAddress;
address[] public addressBook;
event GenericERC721created(address deployedProxyAddress);
constructor(address _proxyAddress, address _logicAddress) {
proxyAddress = _proxyAddress;
logicAddress =_logicAddress;
}
function createProxy(
address _owner,
string calldata _name,
string calldata _symbol
) public onlyOwner {
address clone = createClone(proxyAddress);
ERC1967Proxy(clone).constructor(logicAddress, abi.encodeWithSignature("initialize(address,string,string)", _owner, _name, _symbol));
addressBook.push(clone);
emit GenericERC721created(clone);
}
}

Related

Chainlink node external adapter executes successfully, but keeps returning 0

I'm trying to build an external adapter for a chainlink node to import API information. On the chainlink node and API, everything seems like it worked, however when I try to call the stored value from the smart contract, it's always 0 despite the logs indicating that it ran successfully.
type = "directrequest"
schemaVersion = 1
name = "Mimi-Fund-EA"
externalJobID = "834d2179-321d-49ac-bf63-140635e3a606"
forwardingAllowed = false
maxTaskDuration = "0s"
contractAddress = "0xAf644831B57E5625ac64cDa68248b810bE4D4D01"
minContractPaymentLinkJuels = "0"
observationSource = """
decode_log [type=ethabidecodelog
abi="OracleRequest(bytes32 indexed specId, address requester, bytes32 requestId, uint256 payment, address callbackAddr, bytes4 callbackFunctionId, uint256 cancelExpiration, uint256 dataVersion, bytes data)"
data="$(jobRun.logData)"
topics="$(jobRun.logTopics)"]
decode_cbor [type=cborparse data="$(decode_log.data)"]
fetch [type=bridge name="mimifund" requestData="{\\"id\\": $(jobSpec.externalJobID), \\"data\\": { \\"year\\": $(decode_cbor.year), \\"discount_rate\\": $(decode_cbor.discount_rate)}}"]
parse [type=jsonparse path="data,result" data="$(fetch)"]
ds_multiply [type="multiply" times=1000000000000000000]
encode_data [type=ethabiencode abi="(uint256 value)" data="{ \\"value\\": $(ds_multiply) }"]
encode_tx [type=ethabiencode
abi="fulfillOracleRequest(bytes32 requestId, uint256 payment, address callbackAddress, bytes4 callbackFunctionId, uint256 expiration, bytes32 data)"
data="{\\"requestId\\": $(decode_log.requestId), \\"payment\\": $(decode_log.payment), \\"callbackAddress\\": $(decode_log.callbackAddr), \\"callbackFunctionId\\": $(decode_log.callbackFunctionId), \\"expiration\\": $(decode_log.cancelExpiration), \\"data\\": $(encode_data)}"
]
submit_tx [type=ethtx to="0xAf644831B57E5625ac64cDa68248b810bE4D4D01" data="$(encode_tx)"]
decode_log -> decode_cbor -> fetch -> parse -> ds_multiply-> encode_data -> encode_tx -> submit_tx
"""
These are the run logs from the Node. Everything compiled just fine and the values look good however, they never update in a smart contract, it's always 0.
This is my smart contract for reference.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.7;
import "#chainlink/contracts/src/v0.8/ChainlinkClient.sol";
import "#chainlink/contracts/src/v0.8/ConfirmedOwner.sol";
import "#openzeppelin/contracts/utils/Strings.sol";
contract mimifundCO2 is ChainlinkClient, ConfirmedOwner {
using Chainlink for Chainlink.Request;
uint256 public volume;
bytes32 private jobId;
uint256 private fee;
event RequestVolume(bytes32 indexed requestId, uint256 volume);
/**
* #notice Initialize the link token and target oracle
*
* Goerli Testnet details:
* Link Token: 0x326C977E6efc84E512bB9C30f76E30c160eD06FB
* Oracle: 0xCC79157eb46F5624204f47AB42b3906cAA40eaB7 (Chainlink DevRel)
* jobId: ca98366cc7314957b8c012c72f05aeeb
*
*/
constructor() ConfirmedOwner(msg.sender) {
setChainlinkToken(0x326C977E6efc84E512bB9C30f76E30c160eD06FB);
setChainlinkOracle(0xAf644831B57E5625ac64cDa68248b810bE4D4D01);
jobId = "834d2179321d49acbf63140635e3a606";
fee = (1 * LINK_DIVISIBILITY) / 10; // 0,1 * 10**18 (Varies by network and job)
}
/**
* Create a Chainlink request to retrieve API response, find the target
* data, then multiply by 1000000000000000000 (to remove decimal places from data).
*/
function requestCO2PricingData(uint256 _year) public returns (bytes32 requestId) {
Chainlink.Request memory req = buildChainlinkRequest(jobId, address(this), this.fulfill.selector);
req.add('year', Strings.toString(_year)); // Chainlink nodes 1.0.0 and later support this format
req.add('discount_rate', '0.0'); // Chainlink nodes 1.0.0 and later support this format
// Sends the request
return sendChainlinkRequest(req, fee);
}
/**
* Receive the response in the form of uint256
*/
function fulfill(bytes32 _requestId, uint256 _volume) public recordChainlinkFulfillment(_requestId) {
emit RequestVolume(_requestId, _volume);
volume = _volume;
}
/**
* Allow withdraw of Link tokens from the contract
*/
function withdrawLink() public onlyOwner {
LinkTokenInterface link = LinkTokenInterface(chainlinkTokenAddress());
require(link.transfer(msg.sender, link.balanceOf(address(this))), 'Unable to transfer');
}
}
I feel like there is some update to either my fulfill function or submit_tx that I need to update, but I am out of ideas about what to change.
I've tried changing all the parameters and both the API and chainlink node accurate update and reflect the correct input. The smart contract seems to work perfectly, it's just that calling volume in the code always returns 0 and I've got no clue what the issue is.
According to your description, Chainlink node received your request and run the job successfully, but failed to write the result back to your contract. There might be multiple reasons, but most likely something is wrong when the Chainlink node calls the function fulfillOracleRequest2 in the Operator.sol and fails to write the result back to your contract.
Please check the following:
Check if you fund your Chainlink node. You can check the balance of the chainlink node in the top right of the Chainlink node UI which is usually with port number 6688(eg. http://localhost:6688). Because the Chainlink node changes the state of the blockchain when calling the function in the contract operator, there has to be a minimum balance of ETH remaining in your Chainlink node. The solution to the issue is just to transfer some ETH(not LINK) tokens to your chainlink node address.
Check if you grant the Chainlink node permission to call function fulfillOracleRequest2 in the contract operator. Search your Chainlink node address in the blockchain explorer like etherscan, goerliscan, polygonscan, etc. and if the node has no permission to call function fulfillOracleRequest, error Fail with error 'Not authorized sender' will be thrown. The solution to the issue is to use the function setAuthorizedSenders to grant the node address permission to call the function fulfillOracleRequest2.

How to burn token of Smart contract from another Smart contract?

Let say there is a BEP20 token (tokenA)on the blockchain with an internal function _burn and a total supply of 100000000 token i want to write a new Smart contract that can burn token TokenA and substract from the supply how can i proceed? I've tried many solutions but still unable to call the function_burn
Since the function is internal, it means it can only be accessed internally within the contract itself or in contracts deriving from it.
You can either use ERC20Burnable extension (link below) or implement the _burn function inside your token contract with external/public modifier. This way, other contracts can call the function.
https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/extensions/ERC20Burnable.sol
ERC20Burnable version:
Token contract:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "#openzeppelin/contracts/token/ERC20/ERC20.sol";
import "#openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol";
contract BurnMe is ERC20, ERC20Burnable {
constructor() ERC20("Burn me", "BURN"){}
function mint() external {
_mint(msg.sender, 10000);
}
}
Burning contract:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "#openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol";
contract BurnOther{
ERC20Burnable _token;
constructor(address token_){
_token = ERC20Burnable(token_);
}
function burnOther(uint256 amount) external {
_token.burnFrom(msg.sender, amount);
}
}
Your contract version:
Token contract:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "#openzeppelin/contracts/token/ERC20/ERC20.sol";
contract BurnMe is ERC20 {
constructor() ERC20("Burn me", "BURN"){}
function mint() external {
_mint(msg.sender, 10000);
}
function burn(address account, uint256 amount) external {
_spendAllowance(account, _msgSender(), amount);
_burn(account, amount);
}
}
Burning contract:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "./burn.sol";
contract BurnOther{
BurnMe _token;
constructor(address token_){
_token = BurnMe(token_);
}
function burnOther(uint256 amount) external {
_token.burn(msg.sender, amount);
}
}
Decreasing supply is already implemented inside _burn function, so no need to worry about that. https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/ERC20/ERC20.sol#L290
Keep in mind that the burning contract needs allowance to spend the owner's tokens. You can do that by using approve function of the token contract with the burning contract's address as the parameter:
While deploying the burning contract, make sure to add the token address as the constructor parameter.

Is this the right way for interacting with a smart contract?

I'm trying to call claimItem function on my ERC721 token. This function basically calls _safeMint() function from OpenZeppelin ERC721 contract. Here is the question. As a first step I managed deploy a contract on polygon mumbai testnet and I can see my contract on polygon scan. But when I tried to call claimItem function, inside a Transaciton Transaction(from:EthereumAddress.fromHex(session!.accounts[0]) ,to:EthereumAddress.fromHex("CONTRACT_ADDRESS"), data: bytes); like this. Transaction completes but NFT is not minted.
Here Are Some Scree Shots
This one is from a successful one (This is deployed and minted with truffle & web3)
This one is from unsuccessful one (This is signed by MetaMask)
I don't know what I'm doing wrong and I'm really new into blockchain.
EDIT Contract
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
import "#openzeppelin/contracts/token/ERC721/ERC721.sol";
import "#openzeppelin/contracts/access/Ownable.sol";
import "#openzeppelin/contracts/utils/Counters.sol";
contract ArtItemNew is ERC721, Ownable {
using Counters for Counters.Counter;
Counters.Counter private _tokenIds;
using Strings for uint256;
// Optional mapping for token URIs
mapping(uint256 => string) private _tokenURIs;
constructor(string memory _tokenName, string memory _tokenSymbol) ERC721(_tokenName, _tokenSymbol) public {
}
function _setTokenURI(uint256 tokenId, string memory _tokenURI)
internal
virtual
{
require(
_exists(tokenId),
"ERC721Metadata: URI set of nonexistent token"
);
_tokenURIs[tokenId] = _tokenURI;
}
function claimItem(string memory tokenURI) public returns (uint256) {
_tokenIds.increment();
uint256 newItemId = _tokenIds.current();
_mint(msg.sender, newItemId);
_setTokenURI(newItemId, tokenURI);
return newItemId;
}
}

i'm addming a value to the contract but i recevie this error "VM error revert"

contract Bank {
address public admin;
constructor() {
admin = msg.sender;
}
mapping (address => uint) balance;
mapping (address => bool) AccountActive;
function closeAccount() public payable{
AccountActive[msg.sender] = false;
//trasfer all the money from an account closed to the admin
payable(admin).transfer(balance[msg.sender]);
}
function viewbalance() public view returns(uint) {
return balance[msg.sender];
}}
when inserting a value before deployment, I get this error, and if I don't do it in this way the balance is 0, why? (sorry for this noob question)
This error is because you can not use an address ether balance from a smart contract. What I mean is that a smart contract cannot transfer ether from one address to another, because it would be really dangerous.
What you can do is to transfer the msg.value, which is the ether sent as the value of the transaction.
By the way, you should check for correct indentation and symbols placement. Those can lead to errors too.
The issue is here:
payable(admin).transfer(balance[msg.sender]);
You want to transfer money from the admin but the admin has no balance. So you need to send money. For this write this function:
function depositMoneyToAdmin() payable public {
// since it is payable, the money that you send would be stored in msg.value
(bool success,) = admin.call{value: msg.value}("");
// then add the owner's balance to the mapping so when u call viewBalance, you get the balance of owner
balance[admin]+=msg.value;
require(success,"Transfer failed!");
}
Avoid using transfer.
https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/

Sending ether from one account to other account

I am using the below code in solidity to transfer ether from one account to another.
I am calling this from the owner's account.
But my ether gets deducted from owners and goes to contract address instead of the receiver/payee account.
function PayCredit(address payable payee, uint money, uint invoiceNum) public payable{
require(msg.sender==owner, "only owner can invoke it");
payee.transfer(address(this).balance);
claims[payee][invoiceNum].isPayed = true;
}
You are sending your ether's to contract address , change address(this) to address .
I would suggest you good practice of sending ether's to other account. Solidity transaction support value as argument and this is good place for sending ether(WEI) to other account . below code snippet will send 12 WEI to other account.
pragma solidity >=0.4.22 <0.6.0;
contract AB {
uint256 num1;
address owner;
constructor() public{
owner = msg.sender;
}
function sendBal(address payable receiver) payable external onlyOwner {
uint256 amount = msg.value;
receiver.transfer(amount);
}