How to use Chainlink AggregatorV3Interface with UUPSUpgradeable? - chainlink

Will Chainlink's AggregatorV3Interface.sol work with an OpenZeppelin upgradable contract?
Do I place the
"priceFeed =
AggregatorV3Interface(0x9326BFA02ADD2366b30bacB125260Af641031331);"
inside the "initializer{}"?
I would like the address "0x9326BFA02ADD2366b30bacB125260Af641031331"
to be upgradable in the next version of the smart contract.
Is there already a way to do so?
Thank you!
Motivation & Justification
I hope that it makes sense to want to "getLatestPrice()" within the smart contract of a new token.
Before deployment, there is no way of knowing the new token's address.
I would like to change the address using the OpenZeppelin upgradable contract under the UUPS proxy pattern.
Is there any example online to update
priceFeed =
AggregatorV3Interface(0x9326BFA02ADD2366b30bacB125260Af641031331); //
Kovan Testnet
on version 2 of the smart contract?
Thank you!
Important Links:
OpenZeppelin Contracts Wizard
get-the-latest-price using Chainlink's AggregatorV3Interface
Deploying an UUPS Upgradable Contract
I have no idea how to work on version 2 of an UUPS Upgradable Contract.
This is where I got stuck using Chainlink's AggregatorV3Interface.sol with every feature selected on OpenZeppelin Contracts Wizard:
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4;
import
"./#openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol";
import "./#openzeppelin/contracts-
upgradeable/token/ERC20/extensions/ERC20BurnableUpgradeable.sol";
import "./#openzeppelin/contracts-
upgradeable/token/ERC20/extensions/ERC20SnapshotUpgradeable.sol";
import
"./#openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import
"./#openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol";
import
"./#openzeppelin/contracts-upgradeable/token/ERC20/extensions/draft-
ERC20PermitUpgradeable.sol"; import "./#openzeppelin/contracts-
upgradeable/token/ERC20/extensions/ERC20VotesUpgradeable.sol"; import
"./#openzeppelin/contracts-
upgradeable/token/ERC20/extensions/ERC20FlashMintUpgradeable.sol";
import
"./#openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import
"./#openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
import
"#chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol";
contract UpToken is Initializable, ERC20Upgradeable,
ERC20BurnableUpgradeable, ERC20SnapshotUpgradeable,
OwnableUpgradeable, PausableUpgradeable, ERC20PermitUpgradeable,
ERC20VotesUpgradeable, ERC20FlashMintUpgradeable, UUPSUpgradeable {
/// #custom:oz-upgrades-unsafe-allow constructor AggregatorV3Interface
internal priceFeed; constructor() initializer {
priceFeed = AggregatorV3Interface(0x9326BFA02ADD2366b30bacB125260Af641031331); //
Kovan Testnet }
function initialize() initializer public {
__ERC20_init("UpToken", "UPT");
__ERC20Burnable_init();
__ERC20Snapshot_init();
__Ownable_init();
__Pausable_init();
__ERC20Permit_init("UpToken");
__ERC20FlashMint_init();
__UUPSUpgradeable_init(); }
function snapshot() public onlyOwner {
_snapshot(); }
function pause() public onlyOwner {
_pause(); }
function unpause() public onlyOwner {
_unpause(); }
function mint(address to, uint256 amount) public onlyOwner {
_mint(to, amount); }
function _beforeTokenTransfer(address from, address to, uint256
amount)
internal
whenNotPaused
override(ERC20Upgradeable, ERC20SnapshotUpgradeable) {
super._beforeTokenTransfer(from, to, amount); }
function _authorizeUpgrade(address newImplementation)
internal
onlyOwner
override {}
// The following functions are overrides required by Solidity.
function _afterTokenTransfer(address from, address to, uint256 amount)
internal
override(ERC20Upgradeable, ERC20VotesUpgradeable) {
super._afterTokenTransfer(from, to, amount); }
function _mint(address to, uint256 amount)
internal
override(ERC20Upgradeable, ERC20VotesUpgradeable) {
super._mint(to, amount); }
function _burn(address account, uint256 amount)
internal
override(ERC20Upgradeable, ERC20VotesUpgradeable) {
super._burn(account, amount); }
function getLatestPrice() public view returns (int) {
(
/uint80 roundID/,
int price,
/uint startedAt/,
/uint timeStamp/,
/uint80 answeredInRound/
) = priceFeed.latestRoundData();
return price; }
}

Recommend you use hardhat with the upgrades plugin (https://docs.openzeppelin.com/contracts/4.x/upgradeable) to achieve this. When you deploy it the first time using hardhat, it will deploy the proxy, the implementation contract (i.e. your token contract) and an admin contract.
See 20:23 onwards in this video: https://www.youtube.com/watch?v=bdXJmWajZRY&t=15s . In fact maybe watch that entire video to get a sense of how to use hardhat with OZ upgradeable contracts.
Then when you get your token contract address, update the token contract as V2, add the contract address as a state variable and (optionally) add a setter function that gives you the ability to update that state variable in future, and deploy V2. You can see how to deploy V2 in that same video I linked above, at [24:30] or so.

Related

How to know which environment/network a NEAR smart-contract is deployed to (AssemblyScript)?

I'm doing some cross contract calls using NEAR and AssemblyScript. I would like to call different accounts based on the environment my smart-contract is deployed to. If the contract is deployed to testnet, I want to call a testnet cross-contract call. If the contract is deployed to mainnet, I want to call a mainnet cross-contract call.
export function callMetaNear(accountId: string): void {
// how to get correct contract name based on where the contract is deployed?
let otherContract: string = 'test.testnet';
if(contractIsDeployedToMainnet) {
otherContract = 'test.near';
}
// cross-contract call example
const itemArgs: AddItemArgs = {
accountId,
itemId: "Sword +9000",
};
const promise = ContractPromise.create(
otherContract,
"addItem",
itemArgs.encode(),
0,
);
promise.returnAsResult();
I will answer my own question, but I'm not sure if it's the best solution. Better answers are welcome.
I figured we can assume the contract is deployed to mainnet if Context.contractName ends with ".near".
import { Context } from 'near-sdk-core';
...
let otherContract: string = 'test.testnet';
if(Context.contractName.endsWith(".near")) {
otherContract = 'test.near';
}

Chainlink Keeper not performing upkeep

I have a contract that is using Chainlink keepers for upkeep but the checkUpKeep/performUpkeep is not running. I have sufficiently funded the upkeep to ensure it has a high balance. The code from the contract was previously deployed, but now contains a minor change (outside the Chainlink functions), and the previous contract is receiving upkeeps. My code for checkUpKeep and performUpKeep are below:
function **checkUpkeep**(bytes calldata /* checkData */) external view override returns (bool upkeepNeeded, bytes memory /* performData */) {
if(lottery_state == LOTTERY_STATE.OPEN){
upkeepNeeded = (block.timestamp - lastTimeStamp) >= duration;
}
else{
upkeepNeeded = false;
}
}
function **performUpkeep**(bytes calldata /* performData */) external override {
require(msg.sender == 0x4Cb093f226983713164A62138C3F718A5b595F73);
lottery_state = LOTTERY_STATE.DRAWING;
Random(random).getRandomNumber();
}
As I mentioned earlier, this code is being used in another contract which is currently receiving upkeep so I am puzzled as to why it is not working in the new contract.
If your upkeeps are not being performed make sure to double-check the next items:
Are Chainlink Keepers currently available on the network you are deploying to?
Is your smart contract KeeperCompatible?
Call checkUpkeep. Did it return true or false?
Can you performUpkeep?
Did you register your contract for upkeeps?
Did you fund it?

What is balanceRecived in solidity? what it will be strore?

i am begginer can any one explain me what is balanceRecived in solidity? what it will be strore?
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.1;
contract SendMoneyExample {
uint public balanceReceived;
function receiveMoney() public payable {
balanceReceived += msg.value;
}
function getBalance() public view returns(uint) {
return address(this).balance;
}
function withdrawMoney() public {
address payable to = payable(msg.sender);
to.transfer(getBalance());
}
}
Each time when someone executes the receiveMoney() function, it happens as a result of a transaction.
A transaction can hold value in the form of the network native currency. Your question is tagged Ethereum, and the native currency for the Ethereum network is ETH. (If the contract was on the Binance Smart Chain network, the native currency would be BNB, the Tron network has TRX, and so on...)
So each time the receiveMoney() function is executed, in adds the current transaction value to the total number hold in balanceReceived.
Example:
First transaction executing receiveMoney(), sending along 1 wei (the smallest unit of ETH). The value of balanceReceived becomes 1.
Second transaction executing receiveMoney(), sending along 5 wei. The value of balanceReceived becomes 6.

Testing error for function call to a non-contract account

While testing our VRF getRandomNumber(s) with test-helpers, we keep on getting Error: Transaction reverted: function call to a non-contract account at:
require(LINK.balanceOf(address(this)) > fee, "Not enough LINK to initialte function call");
LINK seems to be used correctly here. What's the meaning/issue with the non-contract account?
Other tests on the same RandomNumberConsumer object are successful.
contract RandomNumberConsumer is VRFConsumerBase {
[...]
function getRandomNumber(uint256 userProvidedSeed) public returns (bytes32 requestId) {
require(LINK.balanceOf(address(this)) >= fee, "Not enough LINK - fill contract with faucet");
return requestRandomness(keyHash, fee, userProvidedSeed);
}
describe("getRandomNumber()", function() {
it("Should return a requestID", async function() {
const requestId = await randomNumberConsumer.getRandomNumber(12);
// checks on requestId
});
});
Any LINK.xxx() call refers to the external LINK contract which is not existent in your code. It's a contract already deployed on the network - that's why you're most probably passing the LINK address to the constructor of your contract.
To make it work in the test, you need to mock something so that your test doesn't end up calling the real LINK interface. One of the ways would be to mock your getRandomNumber function. Since it's public, that should be easily doable with Waffle's mocking utils: https://ethereum-waffle.readthedocs.io/en/latest/mock-contract.html.
Alternatively (probably more legit, but longer) you can mock the entire LINK contract:
Have some Mocks.sol contract:
pragma solidity ^0.8.7;
import "#chainlink/contracts/src/v0.8/interfaces/LinkTokenInterface.sol";
abstract contract LinkMock is LinkTokenInterface {}
Initialize it as a mock in your test and pass its address to your mock contract as the first argument, as per the VRF documentation:
import { waffle } from 'hardhat'
import { abi as linkMockAbi } from '../artifacts/contracts/Mocks.sol/LinkMock.json'
const [deployer, vrfCoordinatorMock, ...actors] = waffle.provider.getWallets()
const getContract = async ({ mockedLinkBalance }: { mockedLinkBalance: string }) => {
const linkMockContract = await waffle.deployMockContract(deployer, linkMockAbi)
// Mocks the external LINK contract that we don't have access to during tests
await linkMockContract.mock.balanceOf.returns(ethers.utils.parseEther(mockedLinkBalance))
await linkMockContract.mock.transferAndCall.returns(true)
return waffle.deployContract(deployer, ContractJson, [
vrfCoordinatorMock.address,
linkMockContract.address,
'0x0000000000000000000000000000000000000000000000000000000000000000',
'100000000000000000',
])
}
Call rawFulfillRandomness() which the VRF calls itself, whenever you want to mock the VRF generating the randomness:
const contract = await getContract()
await contract.connect(vrfCoordinatorMock).rawFulfillRandomness('0x0000000000000000000000000000000000000000000000000000000000000000', mockedRandomnessValue)
Note I hardcoded requestId for brevity in the above example. You'll have to come up with a way of stubbing it if you rely on its value in your contract.

How to call different contract from its address?

In solidity (ethereum) one needs the contract address to call that contract.
contract KittyInterface {
function getKitty(uint256 _id) external view returns (
bool isGestating,
bool isReady,
uint256 cooldownIndex,
uint256 nextActionAt,
uint256 siringWithId,
uint256 birthTime,
uint256 matronId,
uint256 sireId,
uint256 generation,
uint256 genes
);
}
contract ZombieFeeding is ZombieFactory {
address ckAddress = 0x06012c8cf97BEaD5deAe237070F9587f8E7A266d;
KittyInterface kittyContract = KittyInterface(ckAddress);
Can I do that in near protocol?
The examples in near are something different which requires supplying the wasm file.
https://github.com/near-examples/rust-high-level-cross-contract
pub fn deploy_status_message(&self, account_id: String, amount: u64) {
Promise::new(account_id)
.create_account()
.transfer(amount as u128)
.add_full_access_key(env::signer_account_pk())
.deploy_contract(
include_bytes!("../status-message-contract/status_message.wasm").to_vec(),
);
}
Also, I am getting errors while using the high level cross contract code. https://gateway.ipfs.io/ipfs/QmPvcjeEE5PJvaJNN2axgKVWGbWVEQCe9q4e95t9NCeGFt/
Take a look at the lockup contract example instead. It uses the following:
ext_whitelist::is_whitelisted(
staking_pool_account_id.clone(),
&self.staking_pool_whitelist_account_id,
NO_DEPOSIT,
gas::whitelist::IS_WHITELISTED,
)
.then(ext_self_owner::on_whitelist_is_whitelisted(
staking_pool_account_id,
&env::current_account_id(),
NO_DEPOSIT,
gas::owner_callbacks::ON_WHITELIST_IS_WHITELISTED,
))
from https://github.com/near/core-contracts/blob/cd221798a77d646d5f1200910d45326d11951732/lockup/src/owner.rs#L29-L40
The first call interface is (<arg_0>, <arg_1>, ..., <arg_n>, <ACCOUNT_ID>, <ATTACHED_DEPOSIT>, <ATTACHED_GAS>)
<arg_0>, <arg_1>, ..., <arg_n> - arguments from the interface defined below
<ACCOUNT_ID> - the account where the contract to call is deployed
<ATTACHED_DEPOSIT> - the amount in yocto-NEAR to attach to the call
<ATTACHED_GAS> - the amount of Gas to pass to the call
It later attached a callback to the first promise using .then. The callback is just another async function call.
The high-level interface ext_whitelist is defined like this:
#[ext_contract(ext_whitelist)]
pub trait ExtStakingPoolWhitelist {
fn is_whitelisted(&self, staking_pool_account_id: AccountId) -> bool;
}
from https://github.com/near/core-contracts/blob/cd221798a77d646d5f1200910d45326d11951732/lockup/src/lib.rs#L64-L67

Resources