How to make Node.JS function that calls solidity withdraw function? - javascript

I can't get JS properly to call my solidity function withdraw funds. I have got solidity:
function withdrawFunds() public {
require(msg.sender == owner, "You are not the owner");
(bool success, ) = payable(owner).call {
value: address(this).balance
}("");
require(success);
}
And it works, but I cant figure out how to properly call it in JS.
So far I have this in JS:
const withdrawFunds = async () => {
try {
await Contractoftickets.methods.withdrawFunds().call({
from: address,
})
setSuccessMsg(`Funds withdrawn!`)
}
}
It executes but it currently does not withdraw funds.

With ethers.js you can do it like this:
const withdrawFunds = async () => {
try {
const Contractoftickets = ethers.getContract(contractAddress, contractInterfaceOrABI)
await Contractoftickets.withdrawFunds()
setSuccessMsg(`Funds withdrawn!`)
}
}
I'll recommend you to go through ethers docs for more details. A simple note, you've to install ethers and connect your wallet with it before using it like above.

Related

Defining variable within function in jest

So I just started using jest and I am trying to figure out a difficult problem.
I am working on a Strapi plugin and I am trying to test this function
module.exports = {
async index(ctx) {
let verification = {}
// Checks if there is a captcha provider
console.log('strapi' + strapi)
if (!(strapi.config.get('plugin.ezforms.captchaProvider.name') === 'none') && (strapi.config.get('plugin.ezforms.captchaProvider.name'))) {
verification = await strapi.plugin('ezforms').service(strapi.config.get('plugin.ezforms.captchaProvider.name')).validate(ctx.request.body.token)
//throws error if invalid
if (!verification.valid) {
...
The issue is that the strapi object is injected when running strapi and I want to know how I can inject a fake variable into this function.
I've already implemented a fake strapi object in my test and it looks something like this
test('should return captcha error', async function () {
strapi.plugin().service().validate = jest.fn(function () {
return {
error: {
valid: false,
message: 'Unable to verify captcha',
code: 500
}
}
})
let result = await submitController.index(ctx)
expect(result).toEqual(500)
My issue right now is that when running index() it doesn't have a reference to the Strapi object
describe('Submit Controller', function () {
let strapi
beforeAll(async function () {
strapi = {
...
plugin: function () {
return {
service: function () {
return {
validate: function () {
return {
error: {
valid: false,
message: 'Unable to verify captcha',
code: 500
}
}
}
}
}
}
}
}
})```
I reference in the test file but the `index()` function doesn't have access
[![screenshot][1]][1]
How can I inject my fake Strapi object into the index() function
[1]: https://i.stack.imgur.com/rCc7N.png
Right now it seems that strapi is a free variable for index() method. Due to lexical scope index() method has an access to free variables which were in a scope when the method is defined.
I do not know a structure of your project but as a solution I would recommend to explicitly pass a strapi object as a parameter in index method
module.exports = {
async index(ctx, strapi) {
let verification = {}
// Checks if there is a captcha provider
console.log('strapi' + strapi)
if (!(strapi.config.get('plugin.ezforms.captchaProvider.name') === 'none') && (strapi.config.get('plugin.ezforms.captchaProvider.name'))) {
verification = await strapi.plugin('ezforms').service(strapi.config.get('plugin.ezforms.captchaProvider.name')).validate(ctx.request.body.token)
//throws error if invalid
if (!verification.valid) {
...
Turns out you can pass the strapi object in the root of the module export.
module.exports = ({ strapi }) => ({
async index(ctx) {
...
Then in your test you can do
let result = await submitController({strapi}).index(ctx)

How to get a user's keypair from their public key only (Solana)?

I'm making a dApp and I want to add a button where a user (the one with their wallet connected) can send exactly 0.01 SOL to another user. I already wrote the function in my Rust program and after testing it with anchor test it seems to be working when I use my own personal wallet's Keypair to sign the transaction. However, now I am writing the event handler function in my web app's frontend and I'm not sure what to pass for the signers parameter if I want the user to sign the transaction. What do I pass if I don't know their secret key? Is there a way that I can generate a user's Keypair from their public key alone or would I need to use the Solana Wallet Adapter for this? Any help would be appreciated. This is my first time working with Solana!
This is the function:
const tipSol = async (receiverAddress) => {
try {
const provider = getProvider();
const program = new Program(idl, programID, provider);
const lamportsToSend = LAMPORTS_PER_SOL / 100;
const amount = new anchor.BN(lamportsToSend);
await program.rpc.sendSol(amount, {
accounts: {
from: walletAddress,
to: receiverAddress,
systemProgram: SystemProgram.programId,
},
signers: ?
})
console.log('Successfully sent 0.01 SOL!')
window.alert(`You successfully tipped ${receiverAddress} 0.01 SOL!`)
} catch (error) {
console.error('Failed to send SOL:', error);
window.alert('Failed to send SOL:', error);
}
}
Frontends never access private keys. Instead the flow is something like:
Frontend creates the transaction
Frontend sends the transaction to the wallet
Wallet signs the transaction
Wallet returns the signed transaction to the frontend
Frontend send the transaction
You can use the #solana/wallet-adapter to implement this on your frontend https://github.com/solana-labs/wallet-adapter
In practice it would be something like this in your frontend
export const Component = () => {
const { connection } = useConnection();
const { sendTransaction } = useWallet();
const handle = async () => {
const ix: TransactionInstruction = await tipSol(receiverKey);
const tx = new Transaction().add(ix);
const sig = await sendTransaction(tx, connection);
};
// ...
};

How do I listen to events from a smart contract using ethers.js contract.on() in a node.js application?

I'm trying to listen to events emitted from the USDT contract Transfer function using ethers.js (not web3) in a node.js application.
When I run the script, the code runs with no errors and then quickly exits. I'd expect to get the event logs. I'm not sure what step I'm missing.
I've tested this script by calling the getOwner() method and console logging that result, this works fine, so my connection to mainnet is ok.
I'm using alchemy websocket.
My index.js file
const hre = require("hardhat");
const ethers = require('ethers');
const USDT_ABI = require('../abis/USDT_ABI.json')
async function main() {
const usdt = "0xdAC17F958D2ee523a2206206994597C13D831ec7";
const provider = new ethers.providers.WebSocketProvider("wss://eth-mainnet.ws.alchemyapi.io/v2/MY_API");
const contract = new ethers.Contract(usdt, USDT_ABI, provider)
contract.on('Transfer', (from, to, value) => console.log(from, to, value))
}
main()
.then(() => process.exit(0))
.catch(error => {
console.error(error);
process.exit(1);
});
My hardhat.config.js file
require("#nomiclabs/hardhat-waffle");
require('dotenv').config()
// This is a sample Hardhat task. To learn how to create your own go to
// https://hardhat.org/guides/create-task.html
task("accounts", "Prints the list of accounts", async () => {
const accounts = await ethers.getSigners();
for (const account of accounts) {
console.log(account.address);
}
});
// You need to export an object to set up your config
// Go to https://hardhat.org/config/ to learn more
/**
* #type import('hardhat/config').HardhatUserConfig
*/
module.exports = {
paths: {
artifacts: './src/artifacts',
},
networks: {
mainnet: {
url: "wss://eth-mainnet.ws.alchemyapi.io/v2/MY_API",
accounts: [`0x${process.env.PRIVATE_KEY}`]
},
hardhat: {
chainId: 1337
},
},
solidity: "0.4.8"
};`
I solved this by removing
.then(() => process.exit(0))
.catch(error => {
console.error(error);
process.exit(1);
});
and just calling main. It's recommended in the hardhat docs to use the .then and .catch code but when running a long running process like this script does with contract.on(), it causes the script to exit.
I do this:
const ethers = require('ethers');
const abi = [{...}]
const contractAddress = '0x000...'
const webSocketProvider = new ethers.providers.WebSocketProvider(process.env.ETHEREUM_NODE_URL, process.env.NETWORK_NAME);
const contract = new ethers.Contract(contractAddress, abi, webSocketProvider);
contract.on("Transfer", (from, to, value, event) => {
console.log({
from: from,
to: to,
value: value.toString(),
data: event
});
});
The event return all data related to event and transaction.

What functions should I mock during unit testing

I've been reading some articles, and posts here on Stack Overflow about when I should mock a function and when I shouldn't, but I have a case where I'm not sure about what to do.
I have a UserService class which uses dependency injection concept to receive dependencies through its constructor.
class UserService {
constructor(userRepository) {
this.userRepository = userRepository;
}
async getUserByEmail(userEmail) {
// would perform some validations to check if the value is an e-mail
const user = await this.userRepository.findByEmail(email);
return user;
}
async createUser(userData) {
const isEmailInUse = await this.getUserByEmail(userData.email);
if(isEmailInUse) {
return "error";
}
const user = await this.userRepository.create(userData);
return user;
}
}
I want to test if the createUser method works properly, and for my tests, I created a fake userRepository which is basically a object with mocked methods that I will use while instantiating UserService Class
const UserService = require('./UserService.js');
describe("User Service tests", () => {
let userService;
let userRepository;
beforeEach(() => {
userRepository = {
findOne: jest.fn(),
create: jest.fn(),
}
userService = new UserService(userRepository);
});
afterEach(() => {
resetAllMocks();
});
describe("createUser", () => {
it("should be able to create a new user", async () => {
const newUserData = { name: 'User', email: 'user#test.com.br' }
const user = { id: 1, name: 'User', email: 'user#test.com.br' }
userRepository.create.mockResolvedValue(user);
const result = await userService.createUser();
expect(result).toStrictEqual(user);
})
})
})
Note that in the createUser method, there is a call to the getUserByEmail method which is also a method of UserService class, and that is where I got confused.
Should I mock the getUserByEmail method even it is a method of the class I'm testing? If it is not the correct approach, what should I do?
You should almost always prefer not to mock parts of the thing you're supposed to be testing, in this case UserService. To illustrate why, consider these two tests:
Provides a test double implementation for findByEmail on the repo object:
it("throws an error if the user already exists", async () => {
const email = "foo#bar.baz";
const user = { email, name: "Foo Barrington" };
const service = new UserService({
findByEmail: (_email) => Promise.resolve(_email === email ? user : null),
});
await expect(service.createUser(user)).rejects.toThrow("User already exists");
});
Stubs out the service's own getUserByEmail method:
it("throws an error if the user already exists", async () => {
const email = "foo#bar.baz";
const user = { email, name: "Foo Barrington" };
const service = new UserService({});
service.getUserByEmail = (_email) => Promise.resolve(_email === email ? user : null);
await expect(service.createUser(user)).rejects.toThrow("User already exists");
});
For your current implementation, both pass just fine. But let's think about how things might change.
Imagine we need to enrich the user model getUserByEmail provides at some point:
async getUserByEmail(userEmail) {
const user = await this.userRepository.findByEmail(userEmail);
user.moreStuff = await.this.userRepository.getSomething(user.id);
return user;
}
Obviously we don't need this extra data just to know whether or not the user exists, so we factor out the basic user object retrieval:
async getUserByEmail(userEmail) {
const user = await this._getUser(userEmail);
user.moreStuff = await.this.userRepository.getSomething(user.id);
return user;
}
async createUser(userData) {
if (await this._getUser(userData.email)) {
throw new Error("User already exists");
}
return this.userRepository.create(userData);
}
async _getUser(userEmail) {
return this.userRepository.findByEmail(userEmail);
}
If we were using test 1, we wouldn't have to change it at all - we're still consuming findByEmail on the repo, the fact that the internal implementation has changed is opaque to our test. But with test 2, that's now failing even though the code still does the same things. This is a false negative; the functionality works but the test fails.
In fact you could have applied that refactor, extracting _getUser, prior to a new feature making the need so clear; the fact that createUser uses getUserByEmail directly reflects accidental duplication of this.userRepository.findByEmail(email) - they have different reasons to change.
Or imagine we make some change that breaks getUserByEmail. Let's simulate a problem with the enrichment, for example:
async getUserByEmail(userEmail) {
const user = await this.userRepository.findByEmail(userEmail);
throw new Error("lol whoops!");
return user;
}
If we're using test 1, our test for createUser fails too, but that's the correct outcome! The implementation is broken, a user cannot be created. With test 2 we have a false positive; the test passes but the functionality doesn't work.
In this case, you could say that it's better to see that only getUserByEmail is failing because that's where the problem is, but I'd contend that would be pretty confusing when you looked at the code: "createUser calls that method too, but the tests say it's fine...".
You shouldn't mock any of these functions since its creating users and reading data from the database. If you mock them then what's the point of the test. In other words, you wouldn't know if your app is working correctly with the database or not. Anyway, I would mock functions such as the functions that send emails and so on. Don't mock the functions that are the heart of the application. You should have a database for testing and another one for production.

Test AngularFireAuth Wrapper, without using AngularFireAuth mock

I would like to have a AuthWrapper Service that wraps the AngularFireAuth Service. Something like this.
// EDIT: Adding some import statements.
import {TestBed} from '#angular/core/testing';
import { AuthWrapperService } from './auth-wrapper.service';
import {AngularFireModule} from '#angular/fire';
import {AngularFireAuth, AngularFireAuthModule} from '#angular/fire/auth';
import {environment} from '../environments/environment';
#Injectable({
providedIn: 'root'
})
export class AuthWrapper {
constructor(public afAuth: AngularFireAuth) { }
isAuthenticated(): Observable<firebase.User> {
return this.afAuth.user;
}
createUserWithEmailAndPassword(email: string, password: string): Promise<String> {
let authPromise: Promise<firebase.auth.UserCredential> =
this.afAuth.auth.createUserWithEmailAndPassword(email, password);
return authPromise
.then((value) => {
return value.user.email;
})
.catch(function(error) {
return error.message;
});
}
}
I want a wrapper, so that I can test my connection to AngularFireAuth. Other tests mock the AuthWrapper.
( Reason for not mocking AngularFireAuth: Say I mock AngularFireAuth, then I am determining the mock's return values. Then I am saying that I understand what these values would look like. It is not safe to assume this without ever testing these by calling the backend. Say google changes how the results of the real AngularFireAuth's methods, I would then be forced to change the results of each of my AngularFireAuth mocks. Instead it is better to wrap AngularFireAuth in a wrapper, and just change that wrapper's methods to conform to google's changes. )
My tests in Karmine and Jasmine result in an "Async callback was not invoked within 5000ms error." I know the user is signed it because the first expect passes, but how do I get the second expect to work?:
describe('AuthWrapperService', () => {
let fireAuthService: AngularFireAuth;
let password = "dcbA4321!";
beforeEach(() => {
TestBed.configureTestingModule({
imports: [
AngularFireModule.initializeApp(environment.firebase),
AngularFireModule,
AngularFireAuthModule
],
providers: [AngularFireAuth, AuthWrapperService],
declarations: []
})
fireAuthService = TestBed.get(AngularFireAuth);
});
it('should sign in user', async() => {
const email = "anyemail#gmail.com";
let authWrap = new AuthWrapperService(fireAuthService);
let userEmail = await authWrap.createUserWithEmailAndPassword(email, password);
expect(userEmail).toBe("anyemail#gmail.com");
let obs = authWrap.isAuthenticated();
let promise = obs.toPromise();
let user = await promise.then((result) => {return result});
expect(user.email).toBe("anyemail#gmail.com");
});
});
I haven't seen any Angular testing code, where the AngularFireAuth isn't mocked.
These are the tests that worked for me with a time interval of 5000ms. I did test them with "bad#gmail.com" in the expect lines to make sure the expect lines were actually running, and yes, the expect lines are actually passing. I intend to only run the AuthWrapperService tests periodically since they hit the database. I will mock the AuthWrapperService in other tests. Before I run these tests I delete the existing users in the firebase database manually through the firebase console. I do run both of these tests in one go, (inside one describe block).
it('should create new user', async() => {
const annEmail = "ann#gmail.com";
let authWrap = new AuthWrapperService(fireAuthService);
await authWrap.createUserWithEmailAndPassword(annEmail, password).then(
((testEmail) => {
expect(fireAuthService.auth.currentUser.email).toBe(annEmail);
})
)
await fireAuthService.auth.signOut();
});
it('should return error message when user already exists', async() => {
const email = 'ben#gmail.com';
const error = 'already in use';
let authWrap = new AuthWrapperService(fireAuthService);
await authWrap.createUserWithEmailAndPassword(email, password)
.then((value: String) => {
expect(fireAuthService.auth.currentUser.email).toBe(email);
});
await fireAuthService.auth.signOut();
expect(fireAuthService.auth.currentUser).toBeNull();
await authWrap.createUserWithEmailAndPassword(email, password)
.then((value: String) => {
expect(value).toContain('already in use');
});
await fireAuthService.auth.signOut();
});
I decided to use fireAuthService.auth.currentUser.email instead of the AuthWrapperService's isAuthenticated() method to directly test that my AuthWrapperService's createUserWithEmailAndPassword() method creates a user in firebase.
I realize that this is not a unit test, but I have decided that it is better to have an integration test than to mock methods that I don't own.
The following test also worked for me within 5000ms and uses the isAuthenticated() method.
it('should create user cat', async() => {
const catEmail = "cat#gmail.com";
let authWrap = new AuthWrapperService(fireAuthService);
let userEmail = await authWrap.createUserWithEmailAndPassword(catEmail, password);
expect(userEmail).toBe(catEmail);
await authWrap.isAuthenticated().subscribe({
next(user) {
expect(user.email).toBe(catEmail);
}
});
console.log("cat, timeinterval: " + jasmine.DEFAULT_TIMEOUT_INTERVAL);
await fireAuthService.auth.signOut();
});
The following "dan test" resulted in time outs. I tried 29000ms once and it ran out of time. Most runs of this test were 10 seconds. Many times, but not always, this test passes correctly if the user is already a user before the test is run (so it's not really creating a user during the test). One time this test passed correctly when the user had not been created before the test, but I ran this many times without the user existing before the test and it failed. I'm not sure why that would be.
it('should create user dan', done => {
const datEmail = "dan#gmail.com";
let authWrap = new AuthWrapperService(fireAuthService);
authWrap.isAuthenticated().subscribe(
{
next(user){
expect(user.email).toBe(datEmail);
done();
}
}
);
authWrap.createUserWithEmailAndPassword(datEmail, password);
console.log("dan, timeinterval: " + jasmine.DEFAULT_TIMEOUT_INTERVAL);
});
As discussed in comments, its not a good practice to not mock dependencies in case of unit testing. Any cohesive unit should be tested in isolation. And let say if our dependency has number of other dependencies then we cannot provide them all.
When you test the code with the actual dependency, you are not doing unit testing; you are doing integration testing.
Please see this for difference between Integration testing and Unit testing - https://angular.io/guide/testing#use-e2e-end-to-end-to-test-more-than-a-single-unit
You are facing this error because your async spec finishes after the default time out that jasmine has specified, which is 5 seconds. Please find the jasmine documentation on this. URL - https://jasmine.github.io/2.0/introduction.html#section-42
You need to manipulate the jasmine.DEFAULT_TIMEOUT_INTERVAL as per your need, assign it some large value as shown in below example:
describe("long asynchronous specs", function() {
var originalTimeout;
beforeEach(function() {
originalTimeout = jasmine.DEFAULT_TIMEOUT_INTERVAL;
jasmine.DEFAULT_TIMEOUT_INTERVAL = 60000; // 60 second (use value as per need)
});
it("takes a long time", function(done) {
setTimeout(function() {
done();
}, 9000);
});
afterEach(function() {
jasmine.DEFAULT_TIMEOUT_INTERVAL = originalTimeout;
});
});
It still depend on the network as well how fast your promise returns the value. I would suggest you to change the value for jasmine.DEFAULT_TIMEOUT_INTERVAL only in test where you are working with actual dependecies.
I hope this will help.

Categories