I am having trouble calling a simple function from my solidity contract. Here's how the code is structured so far:
In my web3Api.js file I have:
export function getContract(contractDefinition) {
initWeb3();
const contract = initContract(contractDefinition);
contract.setProvider(web3.currentProvider);
if (typeof contract.currentProvider.sendAsync !== 'function') {
contract.currentProvider.sendAsync = function () {
return contract.currentProvider.send.apply(
contract.currentProvider, arguments
);
};
}
return contract.deployed();
}
Then in my projectApi.js file I have:
import { getContract } from './web3Api';
import CompiledContract '../../../build/contracts/compiledContract.json';
let globalVariable;
export async function testing123() {
const contractInstance = await getContract(CompiledContract)
globalVariable = contractInstance;
}
Note: When I call the global variable throughout this file it successfully returns all my contract's functions
TruffleContract {constructor: ƒ, abi: Array(33), contract: Contract, PracticeEvent: ƒ, Transfer: ƒ, …}
So this next part is where I'm running into trouble.
For this post's sake, I am just trying to call this simple function from my contract:
function smartContractFunction() public {
emit PracticeEvent("practice event has been called");
}
Now back in my projectApi.js file I am using the globalVariable to try grab this function from my contract. Here's what I wrote:
export async function practiceInteract() {
const submitTest = await globalVariable.smartContractFunction().call();
console.log(submitTest);
}
When I run the app I get an error saying "formatters.js:274 Uncaught (in promise) Error: invalid address"
Any ideas why I cannot call this solidity function in my projectAPI.js file?
Happy to clarify this if I did not clearly write out my problem.
Thank You!
Your issue is that your are simply not defining an address that is calling the function. You need to defined who is calling the function if you are using web3 in the manner that you are. The correct code would be:
export async function practiceInteract() {
const submitTest = await globalVariable.smartContractFunction().call({from: web3.eth.accounts[0]});
console.log(submitTest);
}
You can do it like this:
const contract = new web3.eth.Contract(ABI, address)
const returnValue = await contract.methods.someFunc(someArg).call()
For more information about how to interact with smart contracts using web3.js, read this article
Related
Im having some issues when using module.exports inside NodeJS, and I've followed multiple guides, and im almost certain Im doing it right.
I have to scripts, main.js and event.js. Im trying to share a function from main.js to event.js, but its not working. Here is the code:
Main.js
function Scan(){
if(fs.readdirSync('./events/').length === 0){
console.log(colors.yellow('Events Folder Empty, Skipping Scan'))
} else {
var events = fs.readdirSync('./events/').filter(file => file.endsWith('.json'))
for(const file of events){
let rawdata = fs.readFileSync('./events/' + file);
let cJSON = JSON.parse(rawdata);
}
events.sort()
tevent = events[0]
StartAlerter()
}
}
module.exports = { Scan };
Event.js
const main = require('../main')
main.Scan;
This returns the error:
(node:19292) Warning: Accessing non-existent property 'Scan' of module exports inside circular dependency
(Use `node --trace-warnings ...` to show where the warning was created)
What am I doing wrong?
I discovered that the arrangement had no effect in the error.
I simply changed the way I exported the function from the Main.js
from:
module.exports = { Scan };
to:
exports.Scan = Scan
And in Event.js, I was able to access the file like this
const main = require("./Main.js");
let result = main.Scan();
This solved my problem, I hope it helps another developer 😎
Problem solved, heres what I did differently:
module.exports = { Scan };
Is declared before the Scan function is defined, like so:
module.exports = { Scan };
function Scan(){
//Code
}
Then in event.js, I wrote
const main = require('../main')
As it is now a module, and can be used with the require() function.
Then to execute the funciton in event.js, I write
main.Scan()
To execute it.
better try :
module.exports = Scan;
I am gonna answer it using a simple example, like in this case below:
File A has 3 functions to process database activity: function
addDB, updateDB, and delData;
File B has 2 functions to process User activity on smartphone:
function addHistory, and editHistory;
Function updateDB in file A is calling function editHis in file B, and function editHistory is calling function updateDB in file A. This is what we called circular-dependency. And we need to prevent it by only giving output of state from editHistory and the rest will be processed inside file A.
//ORIGINAL FUNCTIONS which caused CIRCULAR DEPENDENCY
function updateDB() {
//process update function here
//call function in fileB
const history = require("fileB.js");
await history.editHistory(data).then((output) => {
if(output["message"] === "success"){
response = {
state: 1,
message: "success",
};
}
});
return response;
}
//THIS is the WRONG ONE
function editHistory() {
//process function to edit History here
//call function in fileA
const file = require("fileA.js");
await file.updateDB(data).then((output) => { //You should not call it here
if(output["message"] === "success") {
output = {
state: 1,
message: "success",
};
}
});
return output;
}
//==================================================//
//THE FIX
function updateDB() {
//process function here
const history = require("fileB.js");
await history.editHistory(data).then((output) => {
if(output["message"] === "success"){
await updateDB(data).then((output) => {
response = {
state: 1,
message: "success",
};
});
} else {
log("Error");
}
});
return response;
}
function editHistory() {
//process function to edit History here
// No more calling to function inside the file A
output = {
state: 1,
message: "success",
};
return output;
}
I need to import a JavaScript module from an in memory variable.
I know that this can be done using SystemJS and Webpack.
But nowhere can I find a good working example nor documentation for the same. The documentations mostly talks of dynamic import of .js files.
Basically I need to import the module like below
let moduleData = "export function doSomething(string) { return string + '-done'; };"
//Need code to import that moduleData into memory
If anyone can point to documentation that will be great
There are limitations in the import syntax that make it difficult to do if not impossible without using external libraries.
The closest I could get is by using the Dynamic Import syntax. Two examples follow: the first one is the original I wrote while the second one is an edit from a user that wanted to modernize it.
The original one:
<!DOCTYPE html>
<html>
<head>
<title>Page Title</title>
</head>
<body>
<script>
var moduleData = "export function hello() { alert('hello'); };";
var b64moduleData = "data:text/javascript;base64," + btoa(moduleData);
</script>
<script type="module">
async function doimport() {
const module = await import(b64moduleData);
module.hello();
}
doimport();
</script>
</body>
</html>
The modernized one:
function doimport (str) {
if (globalThis.URL.createObjectURL) {
const blob = new Blob([str], { type: 'text/javascript' })
const url = URL.createObjectURL(blob)
const module = import(url)
URL.revokeObjectURL(url) // GC objectURLs
return module
}
const url = "data:text/javascript;base64," + btoa(moduleData)
return import(url)
}
var moduleData = "export function hello() { console.log('hello') }"
var blob = new Blob(["export function hello() { console.log('world') }"])
doimport(moduleData).then(mod => mod.hello())
// Works with ArrayBuffers, TypedArrays, DataViews, Blob/Files
// and strings too, that If URL.createObjectURL is supported.
doimport(blob).then(mod => mod.hello())
You will however notice that this has some limitations on the way the import code is constructed, which may not precisely match what you need.
The simplest solution is probably to send the code of the module on the server for it to generate a temporary script to be then imported using a more conventional syntax.
let moduleData = await import("data:text/javascript,export function doSomething(str) { return str + '-done'; }");
and to test it
moduleData.doSomething('test');
Use nodejs flag --experimental-modules to use import ... from ...;
node --experimental-modules index.mjs
index.mjs:
import fs from 'fs';
let fileContents = "export function doSomething(string) { return string + '-done'; };"
let tempFileName = './.__temporaryFile.mjs';
fs.writeFileSync(tempFileName, fileContents);
console.log('Temporary mjs file was created!');
import(tempFileName)
.then((loadedModule) => loadedModule.doSomething('It Works!'))
.then(console.log)
Further reading here
How It Works:
I first create the file with fs.writeFileSync
then I use import method's promise to load module and
pipe doSomething method call with "It Works!"
and then log the result of doSomething.
Credits: https://stackoverflow.com/a/45854500/3554534, https://v8.dev/features/dynamic-import, #Louis
NodeJS:
// Base64 encode is needed to handle line breaks without using ;
const { Module } = await import(`data:text/javascript;base64,${Buffer.from(`export class Module { demo() { console.log('Hello World!') } }`).toString(`base64`)}`)
let instance = new Module()
instance.demo() // Hello World!
You can create component and Module on fly. But not from string. Here is an example:
name = "Dynamic Module on Fly";
const tmpCmp = Component({
template:
'<span (click)="doSomething()" >generated on the fly: {{name}}</span>'
})(
class {
doSomething(string) {
console.log("log from function call");
return string + "-done";
}
}
);
const tmpModule = NgModule({ declarations: [tmpCmp] })(class {});
this._compiler.compileModuleAndAllComponentsAsync(tmpModule).then(factories => {
const f = factories.componentFactories[0];
const cmpRef = this.container.createComponent(f);
cmpRef.instance.name = "dynamic";
});
Here is the stackblitz
Based on Feroz Ahmed answer, here is a specific example to dynamically load a Vue 3 component from the server via socket.io.
Server-side (Node + socket.io)
socket.on('give-me-component', (data: any, callback: any) => {
const file = fs.readFileSync('path/to/js/file', 'utf-8');
const buffer = Buffer.from(file).toString('base64');
callback(`data:text/javascript;base64,${buf}`);
});
Client-side (Vue 3 + socket.io-client)
socket.emit('give-me-component', null, async (data: any) => {
// Supposes that 'component' is, for example, 'ref({})' or 'shallowRef({})'
component.value = defineAsyncComponent(async () => {
const imp = await import(data);
// ... get the named export you're interested in, or default.
return imp['TheNamedExport_or_default'];
});
});
...
<template>
<component :is="component" />
</template>
For some weird reason, the suggested way of dynamically import()-ing a "data" URL throws an error: TypeError: Invalid URL when done from an npm package code.
The same "data" URL import()s without any errors from the application code though.
Weird.
const module = await import(`data:text/javascript;base64,${Buffer.from(functionCode).toString(`base64`)}`)
<script type="module">
import { myfun } from './myModule.js';
myfun();
</script>
/* myModule.js */
export function myfun() {
console.log('this is my module function');
}
When I am trying to call one .ts file from another using .Form the following error is occurring
Uncaught (in promise): TypeError: this.Form is undefined
The file that has an error in it
have imported the .ts file to which i want to pass value from this file
import { SawtoothService } from '../sawtooth.service';
Declared Form using a constructor
constructor ( private Form : SawtoothService ) {}
The Function in which another component file function is called
async addForm() {
const proc ="VRT"
const action ="add"
const FAMILYNAME = 'abc'
const servDt =await this.Form.sendData(this.Gender,this.idproof,this.date,this.firstName,proc,action,FAMILYNAME)
this.servicedata="this is service data"+servDt;
alert('SUCCESS!! :-)\n\n' + this.servicedata)
}
there is a function sendData in sawtooth.service.ts file i want to pass data from this file to that file
Depending on how addForm is called, it could be the matter of this context. Try converting it to an async arrow function:
addform = async () => {
const servDt = await
this.Form.sendData(this.Gender,this.idproof,this.date,this.firstName,proc,action,FAMILYNAME)
should be
const servDt = await this.SawtoothService.sendData(this.Gender,this.idproof,this.date,this.firstName,proc,action,FAMILYNAME)
Even though I can't see the rest of the code in this present file. Normally you'd inject the service in your constructor, then you can then call this.name_of_service.any_method_you_created_on_it
I'm having trouble setting up my page object to work. It's probably a simple syntax problem, but I haven't been able to find a solution. I am trying to do something like this:
Test:
test('Verify that a user can update their billing profile', async (t) => {
await t
.billingPage.enterBillingInformation('4111111111111111')
.click(billingPage.saveButton)
.expect(billingPage.successMessage.exists).ok();
});
Page:
import { Selector, t } from 'testcafe';
export default class billingPage {
constructor() {
this.cardNameInput = Selector('#cc_name');
this.cardNumberInput = Selector('#credit-card-number');
this.saveButton = Selector('button').withText('Save Card');
this.successMessage = Selector('div').withText('Your billing information has been successfully updated.');
}
async enterBillingInformation(cardNum) {
await t
.typeText(this.cardNameInput, 'Foo Bar')
.typeText(this.cardNumberInput, cardNum)
}
}
This was working when I had the function contents all within the test, but I want to write a second test with invalid credentials and, obvs, I want to reuse code (the actual function is way longer with many more fields). But I can't figure out what I'm doing wrong.
I get this error:
TypeError: Cannot read property 'enterBillingInformation' of undefined
An example in the docs of how to use methods in the page object would be really helpful! This page seems to show how to set up the function, but there is no corresponding code snippet to show how to actually use it in the test.
http://devexpress.github.io/testcafe/documentation/test-api/test-code-structure.html#test-controller
The "t" object is not known inside the billingPage class. You need to pass it to the enterBillingInformation function from the parent test. Here is complete code:
index.js
import { Selector, ClientFunction } from 'testcafe';
import BillingPage from './billingPage';
const billingPage = new BillingPage();
fixture `Getting Started`
.page `Your page`;
test('Verify that a user can update their billing profile', async t => {
await billingPage.enterBillingInformation("4111111111111111", t);
await t
.click(billingPage.saveButton)
.expect(billingPage.successMessage.exists).ok();
});
billingPage.js
import { Selector } from 'testcafe';
export default class BillingPage {
constructor () {
this.cardNameInput = Selector('#cc_name');
this.cardNumberInput = Selector('#credit-card-number');
this.saveButton = Selector('button').withText('Save Card');
this.successMessage = Selector('div').withText('Your billing information has been successfully updated.');
}
async enterBillingInformation(cardNum, t) {
await t
.typeText(this.cardNameInput, 'Foo Bar')
.typeText(this.cardNumberInput, cardNum)
}
}
You can learn more about the TestCafe Page model here.
I have 2 functions defined like this:
export function builder(){ ... };
export function action() { return () => builder() };
Now I am trying to write a test that mock the builder function and return {};
import * as m from 'redux/modules/mymodule';
it('call buildSolrUrl', () => {
const spy = expect.spyOn(m, "builder").andReturn({});
m.action()();
expect(spy.calls.length).toEqual(1);
});
The problem is that builder does not get mock in that case.
If I change my code for:
export function action() { return () => this.builder() };
The method is mocked but my program does not work anymore because action() return a function that is executed later and this is not resolved to the right object.
To resume: My code works because the call to builder() is done via closure.
The tests are unable to mock the function that way because the function is called via the closure.
What is the best way to deal with this?