If you are asking how to sign a transaction through wallets? For example, metamask, you can follow the code below.
const foo = async (params) => {
const provider = new ethers.providers.Web3Provider(window.ethereum);
await provider.send("eth_requestAccounts", []);
const signer = provider.getSigner();
const Add = "<Contract Address>";
const contract = new ethers.Contract(
Add,
contractABI,
signer
);
let tx = await contract.writeFoo(params);
await tx.wait();
}
--
const foo = async (params) => {
const provider = new ethers.providers.Web3Provider(window.ethereum);
await provider.send("eth_requestAccounts", []);
const Add = "<Contract Address>";
const contract = new ethers.Contract(
Add,
contractABI,
provider
);
let tx = await contract.readFoo(params);
await tx.wait();
}
If you read two code snippets carefully, you will observe that when I was trying to get contract instance, in the first snippet, I used address, contractABI, and signer. While in the second snippet, I used address, contractABI, and provider.
While you are writing a transaction, you need to sign the transaction that is why I passed the signer(if you do this, metamask will ask your permission).
While In the second contract, I am just reading(readFoo) so I do not have to sign, thus I passed provider. It is entierly upto the situation which one to use.
Tell me if it helps!
EDIT:
That is even easier than former. All you have to do is, create wallet instance and sign in through programatically even before deploying. Just know, without interface, you have to sign in using the private address.
const { ethers } = require("ethers");
require("dotenv").config();
const { GOERLI_PRIVATE_KEY, ALCHEMY_API_KEY } = process.env;
const provider = new ethers.providers.JsonRpcProvider(
`https://eth-goerli.alchemyapi.io/v2/${ALCHEMY_API_KEY}`
);
const sender = "0xe515E4883c503584e2DfbdAF60149DAbc123657b";
const receiver = "0x2F600dFC67E8AFDbCb650790c13cB94178871C7B";
const wallet = new ethers.Wallet(GOERLI_PRIVATE_KEY, provider);
const address = "0x326C977E6efc84E512bB9C30f76E30c160eD06FB";
const abi = [
"function balanceOf(address) view returns(uint)",
"function transfer(address to, uint amount) returns(bool)",
];
const contract = new ethers.Contract(address, abi, provider);
const main = async () => {
const senderBefore = await contract.balanceOf(sender);
const receiverBefore = await contract.balanceOf(receiver);
console.log(
`Sender balance before the transfer is: ${ethers.utils.formatEther(
senderBefore
)}`
);
console.log(
`Receiver balance before the transfer is: ${ethers.utils.formatUnits(
receiverBefore,
"ether"
)}`
);
const amount = ethers.utils.parseEther("5");
const contractWithWallet = contract.connect(wallet);
const tx = await contractWithWallet.transfer(receiver, amount);
await tx.wait();
console.log(tx);
const senderAfter = await contract.balanceOf(sender);
const receiverAfter = await contract.balanceOf(receiver);
console.log(
`Sender balance before the transfer is: ${ethers.utils.formatEther(
senderAfter
)}`
);
console.log(
`Receiver balance before the transfer is: ${ethers.utils.formatUnits(
receiverAfter,
"ether"
)}`
);
};
main().catch((error) => {
console.log(error);
process.exit(1);
});
This is a little big code it will answer your problem. There are few things that will change if you are signing from backend. First of all, you need node provider. I have used alchemy here, you can use one to your convience.
Second, you need your private key. In this case, I will suggest you to create .env file and store your private address, alchemy api etc.
Because it is more secure if you are uploading your app in the github and you can always add .env file to .gitignore file to stop from pushing.
So to sign from the backend first you use the ethers.wallet method with private key and provider as arguments.
However, that is just creating the wallet
with your private address but you aren't really signing it.
To sign, you use the following method .connect
.
const contractWithWallet = contract.connect(wallet);
With that you signed with custom address. From now on, you can use the smart contract functions that needs sign in from the user.
In your case:
const tx = await contractWithWallet.sign(abi, rawTransaction, keys);
This is it. If you want you can also pass custom private key like this.
const init = async (PRIVATE_KEY) => {
const wallet = new ethers.Wallet(`${PRIVATE_KEY}`, provider);
......
// Here you can connect the wallet with the contract and call the
function in the contract.
}
EDIT2:
In hardhat, as long as you have custom provider APIs, you can add as many as providers you want.
Below, I have shared my hardhat.config.json file. There you can see how I added multiple providers.
const {
GOERLI_PRIVATE_KEY,
ALCHEMY_API_KEY,
QUICKNODE_API_KEY,
} = process.env;
module.exports = {
solidity: "0.8.9",
networks: {
goerli: {
url: `https://eth-goerli.alchemyapi.io/v2/${ALCHEMY_API_KEY}`,
accounts: [GOERLI_PRIVATE_KEY],
},
bsctest: {
url: `https://radial-wispy-dinghy.bsc-testnet.discover.quiknode.pro/${QUICKNODE_API_KEY}`,
accounts: [GOERLI_PRIVATE_KEY],
},
},
That is how you add providers for starters. Then when you are trying to deploy the contract, it will be following steps.
- Write contract
- Create deploy.js file in scripts folder.
- deploy it using terminal.
From the root folder, you will run this command.
npx hardhat run scripts/deploy.js --network goerli
npx hardhat run scripts.deploy.js --network bsctest
First one for goerli. You can give the custom names you want. And second one for bsc test net.
You can also directly verify the contracts directly from the hardhat terminal without going to the etherscan or bscscan. Take a look at this.
Hardhat verify
Getting started with hardhat
Hardhat documentation
Hardhat has the best documentation. You can find most references there. Try looking there for deep understanding.
Hardhat custom provider
Tutorials - you can find most of the useful tutorisals here.
provide capability to the custom provider function to accept the raw
transaction data, which will internally be signed using our own
library and then sent to the blockchain
Whatever your requirements are, you will do that in deploy.js file using ether.js. You can only deploy using those commands above and you can use raw transaction data to pass to new function to sign in javascript file.
Raw Transactions
Well, is that what you are looking for?