Testing error for function call to a non-contract account - chainlink

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.

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';
}

interaction between the oracle smart contract and the oracle service

I want to use this code to recover the temperature and return the result to the smart contract
contract CMCOracle {
// Contract owner address public owner;
// BTC Marketcap Storage uint public btcMarketCap;
// Callback function event CallbackGetBTCCap();
function CMCOracle() public {
owner = msg.sender;
}
function updateWe() public {
// Calls the callback function
CallbackGetBTCCap();
}
function setBTCCap(uint cap) public {
// If it isn't sent by a trusted oracle
// a.k.a ourselves, ignore it
require(msg.sender == owner);
btcMarketCap = cap;
}
function getBTCCap() constant public returns (uint) {
return btcMarketCap;
}
}
var fetch = require('fetch')
var OracleContract = require('./build/contracts/CMCOracle.json')
var contract = require('truffle-contract')
var Web3 = require('web3');
var web3 = new Web3(new Web3.providers.HttpProvider('https://localhost:8545'));
// Truffle abstraction to interact with our
// deployed contract
var oracleContract = contract(OracleContract);
oracleContract.setProvider(web3.currentProvider);
// Dirty hack for web3#1.0.0 support for localhost testrpc
// see https://github.com/trufflesuite/truffle-contract/issues/56#issuecomment-331084530
if (typeof oracleContract.currentProvider.sendAsync !== "function") {
oracleContract.currentProvider.sendAsync = function() {
return oracleContract.currentProvider.send.apply(
oracleContract.currentProvider, arguments
);
};
}
// Get accounts from web3 web3.eth.getAccounts((err, accounts) => {
oracleContract.deployed().then((oracleInstance) => {
// Watch event and respond to event
// With a callback function
oracleInstance.CallbackGetBTCCap()
.watch((err, event) => {
// Fetch data
// and update it into the contract
fetch.fetchUrl('https://api.coinmarketcap.com/v1/global/',(err, m, b)=> {
const cmcJson = JSON.parse(b.toString());
const btcMarketCap = parseInt(cmcJson.total_market_cap_usd);
// Send data back contract on-chain
oracleInstance.setBTCCap(btcMarketCap, {from: accounts[0]});
})
})
}).catch((err) => { console.log(err) });
but I can't understand how to change the code.
How does the smart contract pass a city whose temperature I want to know to the oracle service?
What API does the oracle service use to fetch the temperature from the external source?
How should i change this code?
source: https://kndrck.co/posts/ethereum_oracles_a_simple_guide/
A smart contract does not interact with the API but the Oracle itself. Normally, it should have been two different contracts like one of the contracts should be separated from the external world. Oracle contract is the API for blockchain, which is basically residing in the blockchain. You can reach out to the contract by means of contract wrapper libraries (web3j, ethereumj)
The contract wrapper will fetch the data from API as JSON. And then the application will convert the data into primitive data that has been defined in the Solidity language. Once it is done, data will send via emit-event functions continuously to the blockchain as long as the application fetched data from the API. In the end, you will have a deterministic database source so that you can copy this source and transfer another place as it is.
For instance, you may change the API endpoint called "https://api.coinmarketcap.com/v1/global/" with "api.openweathermap.org/data/2.5/weather" and data structures (link: https://openweathermap.org/current).

Handle data after http get request in angular

I have a service that requests data from a get method, I'd like to map the response to an object storing some Ids and use those Ids to make other http requests.
I was told this isn't usually done in a callback manner, I looked at this How do I return the response from an asynchronous call? but I don't think it's the usual way to implement services, any hints are very appreciated.
Tried adding in onInit/constructor method in angular to be sure the object was filled before other methods were called without success.
#Injectable ()
export class ContactService {
storeIds;
getIds(callback: Function) {
this.http.get<any>(IdsUrl, Config.options).subscribe(res => {
callback(response);
});
getIds(res => {
this.storeIds = {
profileId: res.profile,
refIds: res.refIds
}
}
)
// this.storeIds returns undefined as it's an async call
this.http.post<any>(WebserviceUrl + this.storeIds.profileId , data, headers )
// .....Many other web services that relay on this Ids
}
Just create another service called StoreIdsService. Update the response you get from your first api call 'getIds' in the StoreIdsService. The idea is to have StoreIdsService as singleton service to keep state of your storeIds. You can inject StoreIdsService in anywhere component you want to get the storeIds.
Its one of manyways to share data in angular between components.
Please refer to this answer someone has posted.
How do I share data between components in Angular 2?
You can simply assign the service response to the storeIds property inside the subscribe method. and call the subsequent services inside it if you need.
#Injectable ()
export class ContactService {
storeIds;
getIds() {
this.http.get<any>(IdsUrl, Config.options).subscribe(res => {
this.storeIds = {
profileId: response.profile,
refIds: response.refIds
}
this.otherapicall1();
this.otherapicall2();
});
}

Using fetch, why do I need so many "await" statements?

I have a fetch instruction in one function that grabs an API key from a server and it's used by a few other objects to deliver that API key to whatever service needs it.
export default async function getAPIKey(key) {
return await (await fetch('http://localhost:8000/' + key)).json();
}
And in my weather object:
export default {
URI: 'https://api.openweathermap.org',
getLocalWeather: async function(city=null, countryCode=null) {
try {
// fetch the API key from environment
const API_KEY = await getAPIKey('wx');
//... rest of code
The code as it is works, but I don't understand why I need 3 await statements. Wouldn't I only need two? I need one for the fetch() in getAPIKey(). Then .json() returns a promise because it has to wait for the response body, so I'd need an await where I call the function in getLocalWeather(). But if I don't have two awaits in getAPIKey() it just returns [object Response]?
Essentially I'm wondering why the following is wrong:
export default async function getAPIKey(key) {
return (await fetch('http://localhost:8000/' + key)).json();
}
And in my weather object:
export default {
URI: 'https://api.openweathermap.org',
getLocalWeather: async function(city=null, countryCode=null) {
try {
// fetch the API key from environment
const API_KEY = await getAPIKey('wx');
//... rest of code
Am I miss-counting? Because I only see two Promises. I know async/await functions are promises under the hood, so getAPIKey() is a promise, but wouldn't that promise be the .json() Promise? And if so why isn't the await where I call the function sufficient?
I'm not sure what what I'm failing to understand.
You don't need any of those await statements inside of getAPIKey() and your function doesn't even need to be async. You can just do this:
export default function getAPIKey(key) {
return fetch('http://localhost:8000/' + key).json();
}
You just want to return the promise from fetch().json().
The code as it is works, but I don't understand why I need 3 await statements. Wouldn't I only need two?
Actually, you only need one when you do await getAPIKey(). The others inside of getAPIKey() are not needed at all.
When you do something like:
export default async function getAPIKey(key) {
return await fetch('http://localhost:8000/' + key).json();
}
You're just adding a superfluous await that has no benefit. The function returns a promise (all async functions return a promise) and that promise is resolved when the await is done which is exactly the same as just doing return fetch('http://localhost:8000/' + key).json(); in the first place. Adding the second await also adds no value.

Single AWS Lambda function to respond to Alexa skill requests, and return a JSON object, depending on how it is called

I am trying to use the same AWS Lambda function to do two things with the same DynamoDB dataset.
(a) Provide Alexa Skill Responses
I have already implemented this, and the Skill is operating correctly. I am using NodeJS and the Amazon Skills Kit version 2. The last few lines of my index.js are as follows:
const skillBuilder = Alexa.SkillBuilders.standard();
exports.handler = skillBuilder
.addRequestHandlers(
LaunchRequest,
HelpIntent,
// .... various other intents
UnhandledIntent
)
.addErrorHandlers(ErrorHandler)
.lambda();
(b) Provide a JSON object summarising some database contents
The NodeJS code I have set up for the Alexa skill, processes DynamoDB data in order to provide the skill responses. I want to use the same codebase (i.e. the same Lambda function) to produce summaries for my own benefit. I don't want to copy-paste pieces of the Lambda function into a separate function. I would much rather have the same code do both tasks, in order to keep everything in step.
My problem is that the structure of the Lambda code for returning this JSON response to my request is as follows, from https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-create-api-as-simple-proxy-for-lambda.html:
'use strict';
console.log('Loading hello world function');
exports.handler = function(event, context, callback) {
let name = "you";
let city = 'World';
// etc ... more code ...
callback(null, response);
};
Both pieces of code assign a function to `exports.handler`
I think I want to achieve this effect:
if ( /* test whether being called by Alexa or by API Gateway */ )
{ /* Make the Alexa Response */ }
else
{ /* Construct the JSON data summary response */ }
From what I can make out, each Lambda function (in the sense of each Amazon Resource Number for a Lambda function) has to have only one entry file, i.e. I can't make Lambda start index_Alexa.js versus index_JSON.js.
I am open to any suggestion on how to get the same Lambda function (in the sense of the same JS file or package of files) do both things.
I question the usefulness of the approach somewhat, and the following has some potential for optimization remaining, but one way of accomplishing this is to declare exports.handler as a simple wrapper that invokes the correct previously-declared handler function based on a condition you can test in the request.
// set up handler for alexa
const skillBuilder = Alexa.SkillBuilders.standard();
const alexa_handler = skillBuilder
.addRequestHandlers(
LaunchRequest,
HelpIntent,
// .... various other intents
UnhandledIntent
)
.addErrorHandlers(ErrorHandler)
.lambda();
// set up handler for API Gateway
const api_gateway_handler = function(event, context, callback) {
let name = "you";
let city = 'World';
// etc ... more code ...
callback(null, response);
};
// for each invocation, choose which of the above to invoke
exports.handler = function(event, context, callback) {
if(/* some test that is true only for API Gateway */)
{
api_gateway_handler(event, context, callback);
}
else
{
alexa_handler(event, context, callback);
}
};
The line if(/* some test that is true only for API Gateway */) is something you'll need to work out, but I suspect something like this might work:
if(event.input && event.input.requestContext && event.input.requestContext.apiId)
The API Gateway docs suggest that this value would always be present.

Resources