I am trying to create a raw transaction for sending to the blockchain. In doing so, I want to do this in a browser.
Where can I get nonWitnessUtxo?
All the information that I have outlined here, I found in the tests.
Am I doing the right thing?
const bitcoin = require('bitcoinjs-lib')
const testnet = bitcoin.networks.testnet
const keyPair = bitcoin.ECPair.makeRandom({ network: testnet })
const publicKey = keyPair.publicKey
const { address } = bitcoin.payments.p2pkh({
pubkey: publicKey,
network: testnet
})
const privateKey = keyPair.toWIF()
const psbt = new bitcoin.Psbt({ network: testnet })
const txid = '226a14d30cfd411b14bf20b7ffd211f7f206699690c54d456cc1bef70c2de5a6'
const key = bitcoin.ECPair.fromWIF(privateKey, testnet)
psbt.addInput({
hash: txid,
index: 0,
nonWitnessUtxo: Buffer.from('Where can i get this?', 'hex')
})
psbt.addOutput({
script: Buffer.from('mmpAPZSvhJs1NGw8UaJXEJ9vRByAxProUL', 'hex')
value: 10000
})
psbt.signInput(0, key)
psbt.validateSignaturesOfInput(0)
psbt.finalizeAllInputs()
psbt.extractTransaction().toHex()
I would be grateful for any help!
The nonWitnessUtxo is the full rawtransaction that you are referencing with the input txid.
This answer is for those looking for a way to create a transaction in the browser, but could not deal with the bitcoinjs-lib
I use bitcore-lib - https://www.npmjs.com/package/bitcore-lib
const bitcore = require('bitcore-lib')
const firstPrivateKey = new bitcore.PrivateKey()
const secondPrivateKey = new bitcore.PrivateKey()
const wif = firstPrivateKey.toString()
const toAddress = secondPrivateKey.toAddress().toString()
const satoshiAmount = 10000
const privateKey = bitcore.PrivateKey.fromWIF(wif)
const sourceAddress = privateKey.toAddress(bitcore.Networks.testnet)
const targetAddress = bitcore.Address.fromString(toAddress)
const utxos = [
{
address: 'mywRqUpbENhbu5VsYDwiMTJouVK9g2ZEJQ',
txid: '761693565e82ca176532c52a37fb38cd9f1eb0172a00562b394e60ede0b7df8a',
vout: 1,
scriptPubKey: '76a914ca133ceac705b723b91263aa163ea8a45954e49a88ac',
amount: 0.0001,
satoshis: 10000,
height: 1578273,
confirmations: 338
}
]
const transaction = new bitcore.Transaction()
transaction.from(utxos)
transaction.to(targetAddress, Number(satoshiAmount))
transaction.change(sourceAddress)
transaction.sign(privateKey)
const serializedTX = tx.serialize()
Then you need send this serializedTX as raw transaction to bitcoin network.
P.S. This example does not work because there is an invalid is presented utxos. Get your utxos using API, such as https://bitpay.com/api/addr/${sourceAddress}/utxo and then everything will work.
Related
I want to use the same public-private key to do some encryption/decryption at the code level and want to send encrypted data to the backend along with my public key which I am appending inside of my JWT AUTH Token.
So pls help me to encrypt / decrypt with that approach if possible, as I can't change this code due to reusability
const keyDetails = await window.crypto.subtle.generateKey(
{
name: 'RSASSA-PKCS1-v1_5',
modulusLength: 2048,
publicExponent: new Uint8Array([1, 0, 1]),
hash: { name: 'SHA-256' },
},
true,
['verify', 'sign']
);
I tried that way but got an error.
Also, I want to use my exported public and private keys which I am doing with that approach
const publicKey: any = await window.crypto.subtle.exportKey('jwk', keyDetails.publicKey);
const privateKey: any = await window.crypto.subtle.exportKey('jwk', keyDetails.privateKey);
const enc = new TextEncoder();
const encodedText = enc.encode("testing 1234");
const encryptedText = await window.crypto.subtle.encrypt({
name: "RSASSA-PKCS1-v1_5"
},
publicKey,
encodedText
)
console.log(encryptedText);
const decryptedText = await window.crypto.subtle.decrypt({
name: "RSASSA-PKCS1-v1_5"
},
privateKey,
encryptedText
)
TypeError: Failed to execute 'encrypt' on 'SubtleCrypto': parameter 2 is not of type 'CryptoKey'.
RSASSA-PKCS1-v1_5 is a padding that is applied during signing/verification. It cannot be used for encryption/decryption. The padding for encryption/decryption is RSAES-PKCS1-v1_5, but this is not supported by WebCrypto API. WebCrypto only supports RSAES-OAEP for encryption/decryption. See RFC8017 and WebCrypto API for more details.
Also, the exported JWK keys must first be adapted for encryption/decryption. Then the keys must be imported before they can be used in encryption/decryption.
The following example demonstrates this: First, a key pair for signing/verifying with RSASSA-PKCS1-v1_5 is generated. Both keys are exported as JWK. Then the key_ops and alg parameters are adjusted. Afterwards, the modified keys are re-imported and used for encryption/decryption with RSAES-OAEP:
(async () => {
// Generate
const keyDetails = await window.crypto.subtle.generateKey(
{
name: 'RSASSA-PKCS1-v1_5',
modulusLength: 2048,
publicExponent: new Uint8Array([1, 0, 1]),
hash: { name: 'SHA-256' },
},
true,
['verify', 'sign']
);
console.log(keyDetails)
// Export
const publicKey = await window.crypto.subtle.exportKey('jwk', keyDetails.publicKey);
const privateKey = await window.crypto.subtle.exportKey('jwk', keyDetails.privateKey);
console.log(publicKey)
console.log(privateKey)
// Adapt parameters and import
publicKey.key_ops = ['encrypt'];
privateKey.key_ops = ['decrypt'];
publicKey.alg = 'RSA-OAEP-256';
privateKey.alg = 'RSA-OAEP-256';
const publicKeyReloaded = await window.crypto.subtle.importKey("jwk", publicKey, {name: "RSA-OAEP", hash: {name: "SHA-256"}}, true, ["encrypt"]);
const privateKeyReloaded = await window.crypto.subtle.importKey("jwk", privateKey,{name: "RSA-OAEP", hash: {name: "SHA-256"}}, true, ["decrypt"]);
console.log(publicKeyReloaded)
console.log(privateKeyReloaded)
// Encrypt/Decrypt
const enc = new TextEncoder();
const encodedText = enc.encode("testing 1234");
const encryptedText = await window.crypto.subtle.encrypt({name: "RSA-OAEP"}, publicKeyReloaded, encodedText)
console.log(ab2b64(encryptedText));
const dec = new TextDecoder();
const decryptedText = await window.crypto.subtle.decrypt({name: "RSA-OAEP"}, privateKeyReloaded, encryptedText)
console.log(dec.decode(decryptedText));
// Helper
function ab2b64(arrayBuffer) {
return window.btoa(String.fromCharCode.apply(null, new Uint8Array(arrayBuffer)));
}
})();
Note that in general the same key pair should actually be used for either signing/verifying or encrypting/decrypting, not for both together, see here.
WebCrypto API provides some protection against this misuse by binding the purpose of the key to it (however, this protection can be circumvented all too easily, as shown above).
Well, the answer is already provided by #topaco.
now I Just want to add one more approch here. If someone wants to Encrypt and Decrypt sensitive data with help of [JSON Web Encryption - Ciphertext] JOSE npm lib. with that public/ private key which is generated for sign/ verify only!
const jose = require('jose'); // npm i jose
async encryptDecryptLogic(data: string): Promise<any>{
const keyDetails = await window.crypto.subtle.generateKey(
{
name: 'RSASSA-PKCS1-v1_5',
modulusLength: 2048,
publicExponent: new Uint8Array([1, 0, 1]),
hash: { name: 'SHA-256' },
},
true,
['verify', 'sign']
);
// updating operation from sign-varify to encrypt-decrypt.
// As that private/ public key is generated for sign and verification purposes only but here we extended its purpose. So we need to update a few properties to do encryption/decryption
publicKey.key_ops = ['encrypt'];
privateKey.key_ops = ['decrypt'];
// updating algo from sign-varify[RS256] to encrypt-decrypt[RSA-OAEP]
// Defines the algorithm used to encrypt the Content Encryption Key (CEK). This MUST be set to “RSA-OAEP”.
publicKey.alg = 'RSA-OAEP';
privateKey.alg = 'RSA-OAEP';
const encodedText = await this.jose.jwe.encrypt(publicKey, "lets encrypt me!!")
console.log('encodedText', encodedText);
const decodedText = await this.jose.jwe.decrypt(privateKey, encodedText)
console.log('decodedText', decodedText);
}
I am trying to verify a HMAC signature using the SubtleCrypto API. The whole thing is supposed to run in Cloudflare Workers and I am testing it locally using their wrangler tool.
This is my code so far, but it generates the wrong signature.
const message = "(query params from an url)";
const given_signature = "(extracted from the query params)";
const SECRET = "...";
const algorithm = { name: 'HMAC', hash: 'SHA-256' };
const encoder = new TextEncoder();
const key = await crypto.subtle.importKey(
'raw',
encoder.encode(SECRET),
algorithm,
false,
['sign', 'verify']
);
const signature = await crypto.subtle.sign(
algorithm.name,
key,
encoder.encode(message)
);
const digest = btoa(String.fromCharCode(...new Uint8Array(signature)));
// The digest does not match the signature extracted from the query params
// If I, for example, want to verify the signature directly, the result is still false.
const verify = await crypto.subtle.verify(
algorithm.name,
key,
encoder.encode(given_signature),
encoder.encode(message)
);
If I am using the same secret and message in online HMAC testing tools, I am getting the correct results, so I am certain that there must be a bug in my code.
What I find interesting, is that the signature generated by my code is much shorter than the given one (e.g. 3fn0mhrebHTJMhtOyvRP5nZIhogX/M1OKQ5GojniZTM= vs ddf9f49a1ade6c74c9321b4ecaf44fe67648868817fccd4e290e46a239e26533).
Does anyone have an idea where I am going wrong?
Thanks to the helpful comments! The problem in a nutshell was that the provided signature was encoded as a HEX string, while the generated signature was a base64-encoded string.
To keep things clean, here is a working version that uses the crypto.subtle.verify function:
const message = "(query params from an url w/o the hmac signature)";
const given_signature = "(the given hmac signature extracted from the query params)";
const SECRET = "(my secret key)";
const hexToBuffer = (hex: string) => {
const matches = hex.match(/[\da-f]{2}/gi) ?? [];
const typedArray = new Uint8Array(
matches.map(function (h) {
return parseInt(h, 16);
})
);
return typedArray.buffer;
};
const algorithm = { name: "HMAC", hash: "SHA-256" };
const encoder = new TextEncoder();
const key = await crypto.subtle.importKey(
"raw",
encoder.encode(SECRET),
algorithm,
false,
["sign", "verify"]
);
const result: boolean = await crypto.subtle.verify(
algorithm.name,
key,
hexToBuffer(given_signature),
encoder.encode(message)
);
usually we add a script to our website to track conversion for google analytics. Is there any way send the data from plain javascript code such as in the case of Facebook. for example:
'use strict';
const bizSdk = require('facebook-nodejs-business-sdk');
const Content = bizSdk.Content;
const CustomData = bizSdk.CustomData;
const DeliveryCategory = bizSdk.DeliveryCategory;
const EventRequest = bizSdk.EventRequest;
const UserData = bizSdk.UserData;
const ServerEvent = bizSdk.ServerEvent;
const access_token = '<ACCESS_TOKEN>';
const pixel_id = '<ADS_PIXEL_ID>';
const api = bizSdk.FacebookAdsApi.init(access_token);
let current_timestamp = Math.floor(new Date() / 1000);
const userData = (new UserData())
.setEmails(['joe#eg.com'])
.setPhones(['12345678901', '14251234567'])
// It is recommended to send Client IP and User Agent for Conversions API Events.
.setClientIpAddress(request.connection.remoteAddress)
.setClientUserAgent(request.headers['user-agent'])
.setFbp('fb.1.1558571054389.1098115397')
.setFbc('fb.1.1554763741205.AbCdEfGhIjKlMnOpQrStUvWxYz1234567890');
const content = (new Content())
.setId('product123')
.setQuantity(1)
.setDeliveryCategory(DeliveryCategory.HOME_DELIVERY);
const customData = (new CustomData())
.setContents([content])
.setCurrency('usd')
.setValue(123.45);
const serverEvent = (new ServerEvent())
.setEventName('Purchase')
.setEventTime(current_timestamp)
.setUserData(userData)
.setCustomData(customData)
.setEventSourceUrl('http://jaspers-market.com/product/123')
.setActionSource('website');
const eventsData = [serverEvent];
const eventRequest = (new EventRequest(access_token, pixel_id))
.setEvents(eventsData);
eventRequest.execute().then(
response => {
console.log('Response: ', response);
},
err => {
console.error('Error: ', err);
}
);
or we can do something like:
To send new events, make a POST request to this API's /events edge from this path: https://graph.facebook.com/{API_VERSION}/{PIXEL_ID}/events?access_token={TOKEN}. When you post to this edge, Facebook creates new server events.
I am trying to build a car auction network with composer playground the error occurs when I am at the stage to make an offer to an auction and after that every new registry I try to make gets this error Reference error: require not defined i am familiar with JavaScript but I am not sure what causing this error .
'use strict';
const AdminConnection = require('composer-admin').AdminConnection;
const BusinessNetworkConnection = require('composer-client').BusinessNetworkConnection;
const { BusinessNetworkDefinition, CertificateUtil, IdCard } = require('composer-common');
const path = require('path');
require('chai').should();
const NS = 'org.acme.vehicle.auction';
describe('CarAuction', () => {
// In-memory card store for testing so cards are not persisted to the file system
const cardStore = require('composer-common').NetworkCardStoreManager.getCardStore( { type: 'composer-wallet-inmemory' } );
let adminConnection;
let businessNetworkConnection;
before(async () => {
// Embedded connection used for local testing
const connectionProfile = {
name: 'embedded',
'x-type': 'embedded'
};
// Generate certificates for use with the embedded connection
const credentials = CertificateUtil.generate({ commonName: 'admin' });
// PeerAdmin identity used with the admin connection to deploy business networks
const deployerMetadata = {
version: 1,
userName: 'PeerAdmin',
roles: [ 'PeerAdmin', 'ChannelAdmin' ]
};
const deployerCard = new IdCard(deployerMetadata, connectionProfile);
deployerCard.setCredentials(credentials);
const deployerCardName = 'PeerAdmin';
adminConnection = new AdminConnection({ cardStore: cardStore });
await adminConnection.importCard(deployerCardName, deployerCard);
await adminConnection.connect(deployerCardName);
});
beforeEach(async () => {
businessNetworkConnection = new BusinessNetworkConnection({ cardStore: cardStore });
const adminUserName = 'admin';
let adminCardName;
let businessNetworkDefinition = await BusinessNetworkDefinition.fromDirectory(path.resolve(__dirname, '..'));
// Install the Composer runtime for the new business network
await adminConnection.install(businessNetworkDefinition);
// Start the business network and configure an network admin identity
const startOptions = {
networkAdmins: [
{
userName: adminUserName,
enrollmentSecret: 'adminpw'
}
]
};
const adminCards = await adminConnection.start(businessNetworkDefinition.getName(), businessNetworkDefinition.getVersion(), startOptions);
// Import the network admin identity for us to use
adminCardName = `${adminUserName}#${businessNetworkDefinition.getName()}`;
await adminConnection.importCard(adminCardName, adminCards.get(adminUserName));
// Connect to the business network using the network admin identity
await businessNetworkConnection.connect(adminCardName);
});
describe('#makeOffer', () => {
it('should add the offer to the offers of a vehicle listing', async () => {
const factory = businessNetworkConnection.getBusinessNetwork().getFactory();
// create the auctioneer
const seller = factory.newResource(NS, 'Member', 'daniel.selman#example.com');
seller.firstName = 'Dan';
seller.lastName = 'Selman';
seller.balance = 0;
// create the vehicle
const vehicle = factory.newResource(NS, 'Vehicle', 'CAR_001');
vehicle.owner = factory.newRelationship(NS, 'Member', seller.$identifier);
// create the vehicle listing
const listing = factory.newResource(NS, 'VehicleListing', 'LISTING_001');
listing.reservePrice = 100;
listing.description = 'My nice car';
listing.state = 'FOR_SALE';
listing.vehicle = factory.newRelationship(NS, 'Vehicle', 'CAR_001');
// create the buyer
const buyer = factory.newResource(NS, 'Member', 'sstone1#example.com');
buyer.firstName = 'Simon';
buyer.lastName = 'Stone';
buyer.balance = 1000;
// create another potential buyer
const buyer2 = factory.newResource(NS, 'Member', 'whitemat#example.com');
buyer2.firstName = 'Matthew';
buyer2.lastName = 'White';
buyer2.balance = 100;
// create the auctioneer
const auctioneer = factory.newResource(NS, 'Auctioneer', 'boss#auction.com');
auctioneer.firstName = 'Mr';
auctioneer.lastName = 'Smith';
const offer = factory.newTransaction(NS, 'Offer');
offer.member = factory.newRelationship(NS, 'Member', buyer.$identifier);
offer.listing = factory.newRelationship(NS, 'VehicleListing', 'LISTING_001');
offer.bidPrice = 200;
// Get the registries.
const vehicleRegistry = await businessNetworkConnection.getAssetRegistry(NS + '.Vehicle');
const vehicleListingRegistry = await businessNetworkConnection.getAssetRegistry(NS + '.VehicleListing');
const userRegistry = await businessNetworkConnection.getParticipantRegistry(NS + '.Member');
const auctioneerRegistry = await businessNetworkConnection.getParticipantRegistry(NS + '.Auctioneer');
// Add the Vehicle to the asset registry.
await vehicleRegistry.add(vehicle);
// Add the VehicleListing to the asset registry
await vehicleListingRegistry.add(listing);
// add the members
await userRegistry.addAll([buyer, buyer2, seller]);
// add the auctioneers
await auctioneerRegistry.addAll([auctioneer]);
// Create the offer transaction and submit
await businessNetworkConnection.submitTransaction(offer);
// Create the offer transaction and submit
const lowOffer = factory.newTransaction(NS, 'Offer');
lowOffer.member = factory.newRelationship(NS, 'Member', buyer2.$identifier);
lowOffer.listing = factory.newRelationship(NS, 'VehicleListing', 'LISTING_001');
lowOffer.bidPrice = 50;
await businessNetworkConnection.submitTransaction(lowOffer);
// get the listing
let newListing = await vehicleListingRegistry.get(listing.$identifier);
// both offers should have been added to the listing
newListing.offers.length.should.equal(2);
// close the bidding
const closeBidding = factory.newTransaction(NS, 'CloseBidding');
closeBidding.listing = factory.newRelationship(NS, 'VehicleListing', 'LISTING_001');
await businessNetworkConnection.submitTransaction(closeBidding);
// get the listing
newListing = await vehicleListingRegistry.get(listing.$identifier);
// the offer should have been added to the listing
newListing.state.should.equal('SOLD');
// get the buyer and seller
const theBuyer = await userRegistry.get(buyer.$identifier);
const theSeller = await userRegistry.get(seller.$identifier);
// check the buyer's balance
theBuyer.balance.should.equal(800);
// check the seller's balance
theSeller.balance.should.equal(200);
// get the vehicle
const theVehicle = await vehicleRegistry.get(vehicle.$identifier);
// check that the buyer now owns the car
theVehicle.owner.getIdentifier().should.equal(buyer.$identifier);
});
describe('#closeBidding', () => {
it('with no bids should result in RESERVE_NOT_MET', async () => {
const factory = businessNetworkConnection.getBusinessNetwork().getFactory();
const seller = factory.newResource(NS, 'Member', 'daniel.selman#example.com');
seller.firstName = 'Dan';
seller.lastName = 'Selman';
seller.balance = 0;
// create the vehicle
const vehicle = factory.newResource(NS, 'Vehicle', 'CAR_001');
vehicle.owner = factory.newRelationship(NS, 'Member', seller.$identifier);
// create the vehicle listing
const listing = factory.newResource(NS, 'VehicleListing', 'LISTING_001');
listing.reservePrice = 100;
listing.description = 'My nice car';
listing.state = 'FOR_SALE';
listing.vehicle = factory.newRelationship(NS, 'Vehicle', vehicle.$identifier);
// Get the registries.
const vehicleRegistry = await businessNetworkConnection.getAssetRegistry(NS + '.Vehicle');
const vehicleListingRegistry = await businessNetworkConnection.getAssetRegistry(NS + '.VehicleListing');
const userRegistry = await businessNetworkConnection.getParticipantRegistry(NS + '.Member');
// Add the Vehicle to the asset registry.
await vehicleRegistry.add(vehicle);
// add the seller to the member registry
await userRegistry.add(seller);
// add the vehicle listing
await vehicleListingRegistry.add(listing);
// close the bidding
const closeBidding = factory.newTransaction(NS, 'CloseBidding');
closeBidding.listing = factory.newRelationship(NS, 'VehicleListing', listing.$identifier);
await businessNetworkConnection.submitTransaction(closeBidding);
// get the listing and check state
const vehicleListing = await vehicleListingRegistry.get(listing.$identifier);
vehicleListing.state.should.equal('RESERVE_NOT_MET');
});
});
});
});
You can't use require in a hyperledger composer business network implementation as you see you get an error because the require keyword is not available.
If you want to learn about blockchain technology then you should not use hyperledger composer because it isn't a blockchain technology. Hyperledger Fabric is a blockchain technology and that would be far more worthwhile investing time to understand.
Hyperledger composer was a framework for business networks that could use hyperledger fabric blockchain technology to provide the persistence, immutability etc of the information that it wanted to store
I am trying to swap ETH for DAI tokens using the UniSwap SDK and javascript, but am getting the following error on running the script.
(node:10096) UnhandledPromiseRejectionWarning: Error: resolver or addr is not configured for ENS name (argument="name", value="", code=INVALID_ARGUMENT, version=contracts/5.0.5)
I have narrowed the error down to the uniswap.swapExactETHForTokens function but I still don't know how to fix it.
Full code: (Private keys are hidden from the code for obvious reasons)
const { ChainId, Fetcher, WETH, Route, Trade, TokenAmount, TradeType, Percent } = require('#uniswap/sdk');
const ethers = require('ethers');
const chainId = ChainId.MAINNET;
const tokenAddress = '0x6B175474E89094C44Da98b954EedeAC495271d0F';
const init = async () => {
const dai = await Fetcher.fetchTokenData(chainId, tokenAddress);
const weth = WETH[chainId];
const pair = await Fetcher.fetchPairData(dai, weth);
const route = new Route([pair], weth);
const trade = new Trade(route, new TokenAmount(weth, '1000000000000'), TradeType.EXACT_INPUT);
const slippageTolerance = new Percent('50', '10000');
const amountOutMin = trade.minimumAmountOut(slippageTolerance).raw;
const path = [weth.address, dai.address];
const to = '';
const deadline = Math.floor(Date.now() / 1000) + 60 * 20;
const value = trade.inputAmount.raw;
const provider = ethers.getDefaultProvider('mainnet', {
infura: 'https://mainnet.infura.io/v3/ba14d1b3cfe5405088ee3c65ebd1d4'
});
const signer = new ethers.Wallet(PRIVATE_KEY);
const account = signer.connect(provider);
const uniswap = new ethers.Contract(
'0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D',
['function swapExactETHForTokens(uint amountOutMin, address[] calldata path, address to, uint deadline) external payable returns (uint[] memory amounts)'],
account
);
const tx = await uniswap.swapExactETHForTokens(
amountOutMin,
path,
to,
deadline,
{ value, gasPrice: 20e9 }
);
console.log(`Transaction hash: ${tx.hash}`);
const receipt = await tx.wait();
console.log(`Transaction was mined in block ${receipt.blockNumber}`);
}
init();
I guess you can replace
const to = ''
by:
const to = process.env.ACCOUNT
providing your account / wallet address to which the targetTokens shall be sent.
In my case, I had directly copy-pasted the router address from the uniswap documentation. So my variable looked something like this:
const routerAddress = "0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D ";
Since there was a space at the end of the string, the ethers.js library confused it for ENS name instead of an address. So I corrected it to this:
const routerAddress = "0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D";
Guess it was a silly mistake, but just watch out for it, in case nothing works!
For those who are facing an INVALID ARGUMENT error, here's what worked for my (using React):
Import router02 :
import UniswapV2Router02 from '#uniswap/v2-periphery/build/UniswapV2Router02.json';
hex function:
const toHex = (currencyAmount) => `0x${currencyAmount.raw.toString(16)}`;
const amountOutMin = toHex(trade.minimumAmountOut(slippageTolerance));
const value = toHex(trade.inputAmount);
connect to blockchain
const provider = ethers.getDefaultProvider('mainnet', {
infura: 'JUST_INFURA_NUMBER eg. xxxxxxxxxx'
});
Get contract and methods:
const abi = UniswapV2Router02['abi'];
const uniswapRouter = new ethers.Contract(
'0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D',
abi,
account); //if this doesnt work, try using provider/signer instead of account
console.log("uniswap contract: ", uniswapRouter);
const tx = await uniswapRouter.swapExactETHForTokens(
amountOutMin,
path,
to,
deadline,
{value, gasPrice: 20e9, gasLimit: 250000}
);
Tutorial code: https://www.youtube.com/watch?v=0Im5iaYoz1Y