How to sign and send transfer transaction using waves-transaction JS library? - javascript

Please help me understand https://testnodes.wavesnodes.com/api-docs/index.html I use this api and this library https://github.com/wavesplatform/waves-transactions
I cannot send a transaction using the manual to the library or directly by POST request for api.
common mistakes:
Error: State check failed. Reason: Script doesn’t exist and proof
Error: State check failed. Reason: Transactions from non-scripted accounts must have exactly 1 proof
A POST request for url / addresses also gives an error. Provided API key is not correct.
Here is my code:
const { transfer, broadcast } = require("#waves/waves-transactions");
const seed =
"ride flee tenant tuna share buyer work west amateur review time kick";
const signedTranserTx = transfer(
{
amount: 1,
recipient: "3NBVqYXrapgJP9atQccdBPAgJPwHDKkh6A8"
},
seed
);
const nodeUrl = "http://testnodes.wavesnodes.com";
broadcast(signedTranserTx , nodeUrl)
.then(resp => console.log(resp))
.catch(err => console.error(err));

If you use Waves transactions api, the request should be signed already and you can post it to /transactions/broadcast. Then you don't need your own node and you don't need your own API Key.
in your code, I see several mistakes here:
You're transferring to MAINNET address using testnet node. you
should use TESTNET address instead. in the reciepent change the
address to an address in testnet and let me know if you still get
any errors. you can create new accounts here
https://testnet.ide.wavesplatform.com/ in the tab accounts on the
top right.
Use https instead of http, const nodeUrl = "https://testnodes.wavesnodes.com/";
Add the chain id('T' for testnet and 'W' for mainnet)
Here is the code:
const { transfer, broadcast } = require("#waves/waves-transactions");
const seed =
"ride flee tenant tuna share buyer work west amateur review time kick";
const signedTranserTx = transfer(
{
amount: 100,
recipient: "3N3pJ8xAnbaSBFdAbnaKe4yu4ZXbYkatMcN"
},
seed
);
const nodeUrl = "https://testnodes.wavesnodes.com";
broadcast({ ...signedTranserTx, chainId: "T" }, nodeUrl)
.then(resp => console.log(resp))
.catch(err => console.error(err));

[Update]
The above code working good. Just a quick update since I see the new testnet URI is below link:
https://nodes-testnet.wavesnodes.com
I mean I have replace from https://testnodes.wavesnodes.com to https://nodes-testnet.wavesnodes.com then it's working maybe because we created the account from the different place.
So this is the final code:
const { transfer, broadcast } = require("#waves/waves-transactions");
const seed =
"ride flee tenant tuna share buyer work west amateur review time kick";
const signedTranserTx = transfer(
{
amount: 100,
recipient: "3N3pJ8xAnbaSBFdAbnaKe4yu4ZXbYkatMcN"
},
seed
);
const nodeUrl = "https://nodes-testnet.wavesnodes.com";
broadcast({ ...signedTranserTx, chainId: "T" }, nodeUrl)
.then(resp => console.log(resp))
.catch(err => console.error(err));

Related

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);
};
// ...
};

VM Exception while processing transaction: revert TransferHelper: TRANSFER_FROM_FAILED when running manipulatePrice.js test for bot.js

I am using the code from Dapp Unversity's trading bot masterclass to try to create a bot that will scan cryptocurrency decentralized exchanges for price differences in token pairs and then execute a smart contract to use a flash loan to profit off of this. When testing, I am able to see run a ganache-cli node and run my scanning bot to listen for swap opportunities on ganache. There is a script designed to create a swap opportunity by swapping a large amount of SHIB for WETH on the test net to see if the smart contract will deploy and execute when a swap opportunity is detected by the bot. However, running this script yields the error
UnhandledPromiseRejectionWarning: Error: Returned error: VM Exception while processing transaction: revert TransferHelper: TRANSFER_FROM_FAILED
Also, in the ganache-cli terminal, I get:
Runtime Error: revert
Revert reason: TransferHelper: TRANSFER_FROM_FAILED
Here are the commands I run to get to the points above:
First, I successfully run ganache-cli -f wss://eth-mainnet.alchemyapi.io/v2/<Your-App-Key> -u 0x0e5069514a3dd613350bab01b58fd850058e5ca4 -p 7545 with my app key.
Then, I successfully run node bot.js in another terminal to scan for swap opportunities on ganache. Finally, I run node scripts\manipulatePrice.JS which outputs "Beginnig Swap... Input token: SHIB Output token: WETH" before outputting the above error.
I have tried using node --trace-warnings to show where the warning was created, but was led nowhere helpful. I am wondering if it has something to do with the Runtime Error: revert message? Below is the code for the manipulatePrice.js script I am trying to run to test my bot. I can attach more code if need be, but don't want to post too much. If anyone has insight as to what or where the issue might be, I would greatly appreciate it!!
require("dotenv").config();
const Web3 = require('web3')
const {
ChainId,
Token,
WETH
} = require("#uniswap/sdk")
const IUniswapV2Router02 = require('#uniswap/v2-periphery/build/IUniswapV2Router02.json')
const IUniswapV2Factory = require("#uniswap/v2-core/build/IUniswapV2Factory.json")
const IERC20 = require('#openzeppelin/contracts/build/contracts/ERC20.json')
// -- SETUP NETWORK & WEB3 -- //
const chainId = ChainId.MAINNET
const web3 = new Web3('http://127.0.0.1:7545')
// -- IMPORT HELPER FUNCTIONS -- //
const { getPairContract, calculatePrice } = require('../helpers/helpers')
// -- IMPORT & SETUP UNISWAP/SUSHISWAP CONTRACTS -- //
const config = require('../config.json')
const uFactory = new web3.eth.Contract(IUniswapV2Factory.abi, config.UNISWAP.FACTORY_ADDRESS) // UNISWAP FACTORY CONTRACT
const sFactory = new web3.eth.Contract(IUniswapV2Factory.abi, config.SUSHISWAP.FACTORY_ADDRESS) // SUSHISWAP FACTORY CONTRACT
const uRouter = new web3.eth.Contract(IUniswapV2Router02.abi, config.UNISWAP.V2_ROUTER_02_ADDRESS) // UNISWAP ROUTER CONTRACT
const sRouter = new web3.eth.Contract(IUniswapV2Router02.abi, config.SUSHISWAP.V2_ROUTER_02_ADDRESS) // UNISWAP ROUTER CONTRACT
// -- CONFIGURE VALUES HERE -- //
const V2_FACTORY_TO_USE = uFactory
const V2_ROUTER_TO_USE = uRouter
const UNLOCKED_ACCOUNT = '0x0e5069514a3Dd613350BAB01B58FD850058E5ca4' // SHIB Unlocked Account
const ERC20_ADDRESS = process.env.ARB_AGAINST
const AMOUNT = '40500000000000' // 40,500,000,000,000 SHIB -- Tokens will automatically be converted to wei
const GAS = 450000
// -- SETUP ERC20 CONTRACT & TOKEN -- //
const ERC20_CONTRACT = new web3.eth.Contract(IERC20.abi, ERC20_ADDRESS)
const WETH_CONTRACT = new web3.eth.Contract(IERC20.abi, WETH[chainId].address)
// -- MAIN SCRIPT -- //
const main = async () => {
const accounts = await web3.eth.getAccounts()
const account = accounts[1] // This will be the account to recieve WETH after we perform the swap to manipulate price
const pairContract = await getPairContract(V2_FACTORY_TO_USE, ERC20_ADDRESS, WETH[chainId].address)
const token = new Token(
ChainId.MAINNET,
ERC20_ADDRESS,
18,
await ERC20_CONTRACT.methods.symbol().call(),
await ERC20_CONTRACT.methods.name().call()
)
// Fetch price of SHIB/WETH before we execute the swap
const priceBefore = await calculatePrice(pairContract)
await manipulatePrice(token, account)
// Fetch price of SHIB/WETH after the swap
const priceAfter = await calculatePrice(pairContract)
const data = {
'Price Before': `1 ${WETH[chainId].symbol} = ${Number(priceBefore).toFixed(0)} ${token.symbol}`,
'Price After': `1 ${WETH[chainId].symbol} = ${Number(priceAfter).toFixed(0)} ${token.symbol}`,
}
console.table(data)
let balance = await WETH_CONTRACT.methods.balanceOf(account).call()
balance = web3.utils.fromWei(balance.toString(), 'ether')
console.log(`\nBalance in reciever account: ${balance} WETH\n`)
}
main()
//
async function manipulatePrice(token, account) {
console.log(`\nBeginning Swap...\n`)
console.log(`Input Token: ${token.symbol}`)
console.log(`Output Token: ${WETH[chainId].symbol}\n`)
const amountIn = new web3.utils.BN(
web3.utils.toWei(AMOUNT, 'ether')
)
const path = [token.address, WETH[chainId].address]
const deadline = Math.floor(Date.now() / 1000) + 60 * 20 // 20 minutes
await ERC20_CONTRACT.methods.approve(V2_ROUTER_TO_USE._address, amountIn).send({ from: UNLOCKED_ACCOUNT })
const receipt = await V2_ROUTER_TO_USE.methods.swapExactTokensForTokens(amountIn, 0, path, account, deadline).send({ from: UNLOCKED_ACCOUNT, gas: GAS });
console.log(`Swap Complete!\n`)
return receipt
}
I ran into this issue for the same bot myself and I found the solution. Instead of using .send you should use .sendSignedTransaction and sign it yourself with the correct parameters. BUT if you are sending from an unlocked account, then use ethers.js to get a signer without knowing the private key!
So, you should replace
await ERC20_CONTRACT.methods.approve(V2_ROUTER_TO_USE._address, amountIn).send({ from: UNLOCKED_ACCOUNT })
const receipt = await V2_ROUTER_TO_USE.methods.swapExactTokensForTokens(amountIn, 0, path, account, deadline).send({ from: UNLOCKED_ACCOUNT, gas: GAS });
With this ethers.js alternative
const { ethers } = require("ethers")
const provider = new ethers.providers.JsonRpcProvider("http://127.0.0.1:8545")
const signer = provider.getSigner(UNLOCKED_ACCOUNT)
console.log(provider.chainId)
/*
Define the above code at the top,
Then put the rest of your code here,
Then use this for the ethers transaction
*/
const approvalReceiptEthers = await signer.sendTransaction({
from: UNLOCKED_ACCOUNT,
to: ERC20_CONTRACT._address,
data: ERC20_CONTRACT.methods.approve(V2_ROUTER_TO_USE._address, web3.utils.fromWei(amountIn).toString()).encodeABI(),
gasLimit: GAS
})
/*
* Verify that your unlocked account is allowed to use the funds
*/
var allowance = await ERC20_CONTRACT.methods.allowance(UNLOCKED_ACCOUNT, V2_ROUTER_TO_USE._address).call()
console.log("ALLOWANCE:\t\t", web3.utils.fromWei(allowance).toString(), 'ether')
console.log("ATTEMPTED AMOUNT:\t", web3.utils.fromWei(amountIn).toString(), 'ether')
const swapReceiptEthers = await signer.sendTransaction({
from: UNLOCKED_ACCOUNT,
to: V2_ROUTER_TO_USE._address,
data: V2_ROUTER_TO_USE.methods.swapExactTokensForTokens(web3.utils.fromWei(amountIn).toString(), 0, path, account, deadline).encodeABI(),
gasLimit: GAS
}).then(console.log)
Note: the following code, will only work provided that you signed the transaction with THE SENDER'S PRIVATE KEY. So, if you are sending a transaction on behalf of your own account, use this code (presumably for bot.js)
const approvalTransaction = {
'from' : 'your account address here',
'to' : ERC20_CONTRACT._address,
'data' : ERC20_CONTRACT.methods.approve(V2_ROUTER_TO_USE._address, web3.utils.fromWei(amountIn).toString()).encodeABI(),
'gas' : GAS
}
const transaction = {
'from' : 'your account address here',
'to' : V2_ROUTER_TO_USE._address,
'data' : V2_ROUTER_TO_USE.methods.swapExactTokensForTokens(web3.utils.fromWei(amountIn).toString(), 0, path, account, deadline).encodeABI(),
'gas' : GAS
}
const signedApprovalTx = await web3.eth.accounts.signTransaction(approvalTransaction, process.env.DEPLOYMENT_ACCOUNT_KEY, )
const signedTx = await web3.eth.accounts.signTransaction(transaction, process.env.DEPLOYMENT_ACCOUNT_KEY)
await web3.eth.sendSignedTransaction(signedApprovalTx.rawTransaction)
const receipt = await web3.eth.sendSignedTransaction(signedTx.rawTransaction)
NOTE: For those of you following the same Trading Bot masterclass, this same logic applies to the bot.js code as well when you execute your trade!.
SUMMARY: If you are sending a signed transaction using an unlocked account with ganache-cli, you will need to use ethers.js to sign the message without knowing the private key. Otherwise if you are sending a signed transaction on behalf of yourself, you can use Web3.js to sign the message with your own private

Solana - How to get the balance from my Phantom wallet?

I'm working on a web app that can connect to Phantom Wallet. I've established the connection and have successfully retrieved the wallet's public key. The problem is, I can't seem to find any solution to get the account balance.
For reference, I wanted to display the account balance just like how solanart.io displays it.
Note that I've gone through all related docs (Solana/web3.js, Solana JSON RPC API etc). Please guide me as I'm still new to JSON RPC API.
For a heads up, I'm using vanilla js.
try {
const resp = window.solana.request({
method: "getAccountTokenBalance",
params: [
id, //wallet's public key
{
encoding: "base58",
},
],
});
console.log(resp);
} catch(err) {
// error message
}
The RPC method that you're using does not exist. You'll want to use getBalance to get the SOL on the wallet: https://docs.solana.com/developing/clients/jsonrpc-api#getbalance
To get all of the non-SOL token balances owned by that wallet, you'll have to use getTokenAccountsByOwner using that wallet id: https://docs.solana.com/developing/clients/jsonrpc-api#gettokenaccountsbyowner
import { useWallet } from '#solana/wallet-adapter-react'
import { LAMPORTS_PER_SOL,clusterApiUrl } from '#solana/web3.js'
import * as anchor from '#project-serum/anchor'
const wallet = useWallet()
const SOLANA_HOST = clusterApiUrl("devnet")
const connection = new anchor.web3.Connection(SOLANA_HOST)
let lamportBalance
if (wallet?.publicKey) {
const balance = await connection.getBalance(wallet.publicKey)
lamportBalance=(balance / LAMPORTS_PER_SOL)
}
This method works for me to get SOL Balance
const [userSOLBalance, setSOLBalance] = useState<number>()
if (wallet.publicKey) {
const SOL = connection.getAccountInfo(wallet.publicKey)
SOL.then((res) => setSOLBalance(res.lamports / LAMPORTS_PER_SOL))
}

Infura calls eth_getBlockByNumber ten times for each eth_call

I am trying to make a simple nextjs API route (https://nextjs.org/docs/api-routes/introduction) that is connected to the Ethereum blockchain to perform a view function (requires no gas) from a smart contract.
I have a system where you can buy the rights to mint a NFT (ERC721), and this functions checks if the user has paid for any collectionIds that is not yet minted.
import Web3 from 'web3'
import { getPaidForCollectionsIds } from '../../database'
const mnemonic2 = 'main check ...'
var HDWalletProvider = require('truffle-hdwallet-provider')
export default async function (req, res) {
const paidFor = await getPaidForCollectionsIds(req.body.userId)
if (paidFor.length < 1) return res.json({ data: [] })
const provider = new HDWalletProvider(mnemonic2, 'https://rinkeby.infura.io/v3/INFURAAPIKEY', 0)
const web3 = new Web3(provider)
const TheContractAddress = '0xfbeF...'
const { abi } = require('../../abis/TheContract.json')
const KS = new web3.eth.Contract(abi, TheContractAddress, {
from: '0x5EE...', // default from address
gasPrice: '20000000000' // default gas price in wei, 20 gwei in this case
})
const unminted = []
await Promise.all(paidFor.data.map(async pf => KS.methods.readCollectionIdIsUsed(pf.collectionId).call().then(d => {
console.log(d, 'readCollectionIdIsUsed', pf.collectionId)
}).catch(e => {
unminted.push(sign)
})
)
}))
res.statusCode = 200
res.json({ data: unminted })
}
here is the code from the readCollectionIdIsUsed method in the smart contract:
mapping (uint256 => bool) collectionIdIsUsed;
function readCollectionIdIsUsed(uint256 collectionId) external view returns (bool res) {
require(collectionIdIsUsed[collectionId], 'This signature has not been used');
res = collectionIdIsUsed[collectionId];
}
This all works fine, except for that after a while, I reach the 100 000 request limit of infura.
infura top methods
I dont know why it is calling eth_getBlockByNumber 10 times for each call, is this necessary or is there a way around it?
Web3.js should not do this for calls, but should do for sends.
This is because when you await any web3.js contract methods, it has internal, somewhat unexpected, implied "wait X number of blocks before tx is confirmed" mechanism and somehow this get triggered, although your example code does not seem to have any contract writes. It is documented here.
Because you are using HTTPS connections instead of WebSocket connection, Web3.js needs to poll the new block numbers for confirmations. But if you switch to WebSocket infura provider, these calls should disappear, as Web3.js can simply subscribe to WebSocket new block detected events.

How to automatically join conversation in Microsoft web chat (bot framework)

I'm using https://github.com/Microsoft/BotFramework-WebChat/blob/master/README.md
I want the bot to receive a "join" message whenever the web-chat widget is displayed on the site.
The idea is that the human does not have to initiate the conversation. The bot can respond to somebody joining the conversation with a welcome message.
How is this possible?
This "Welcome feature" has been a long term discussion and topic since Webchat v3. It looks like it has been fixed 2 days ago with this pull request: https://github.com/Microsoft/BotFramework-WebChat/pull/1286
There is now a sample on how to do that, located here:
https://github.com/Microsoft/BotFramework-WebChat/blob/master/samples/15.d.backchannel-send-welcome-event/index.html
In a few words, the demo is the following:
(async function () {
// In this demo, we are using Direct Line token from MockBot.
// To talk to your bot, you should use the token exchanged using your Direct Line secret.
// You should never put the Direct Line secret in the browser or client app.
// https://learn.microsoft.com/en-us/azure/bot-service/rest-api/bot-framework-rest-direct-line-3-0-authentication
const res = await fetch('https://webchat-mockbot.azurewebsites.net/directline/token', { method: 'POST' });
const { token } = await res.json();
// We are using a customized store to add hooks to connect event
const store = window.WebChat.createStore({}, ({ dispatch }) => next => action => {
if (action.type === 'DIRECT_LINE/CONNECT_FULFILLED') {
// When we receive DIRECT_LINE/CONNECT_FULFILLED action, we will send an event activity using WEB_CHAT/SEND_EVENT
dispatch({
type: 'WEB_CHAT/SEND_EVENT',
payload: {
name: 'webchat/join',
value: { language: window.navigator.language }
}
});
}
return next(action);
});
window.WebChat.renderWebChat({
directLine: window.WebChat.createDirectLine({ token }),
store
}, document.getElementById('webchat'));
document.querySelector('#webchat > *').focus();
})().catch(err => console.error(err));
Please note that due to the fact that this PR is quite new, it's not embedded in the latest release so you have to point to the master version of webchat.js file, not latest:
<script src="https://cdn.botframework.com/botframework-webchat/master/webchat.js"></script>
And it's working: your bot side is notified of an activity of type Event, where you will be able to reply to your user, before he typed anything:

Categories