@ethersproject/abstract-provider#TransactionRequest TypeScript Examples
The following examples show how to use
@ethersproject/abstract-provider#TransactionRequest.
You can vote up the ones you like or vote down the ones you don't like,
and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: Provider.ts From evm-provider.js with Apache License 2.0 | 6 votes |
async _resolveTransaction(
tx: Deferrable<TransactionRequest>
): Promise<Deferrable<TransactionRequest>> {
for (const key of ['gasLimit', 'value']) {
const typeKey = key as 'gasLimit' | 'value';
if (tx[typeKey]) {
if (BigNumber.isBigNumber(tx[typeKey])) {
tx[typeKey] = (tx[typeKey] as BigNumber).toHexString();
} else if (isNumber(tx[typeKey])) {
tx[typeKey] = numberToHex(tx[typeKey] as number);
}
}
}
delete tx.nonce;
delete tx.gasPrice;
delete tx.chainId;
return tx;
}
Example #2
Source File: base-provider.ts From bodhi.js with Apache License 2.0 | 6 votes |
call = async (
transaction: Deferrable<TransactionRequest>,
_blockTag?: BlockTag | Promise<BlockTag>
): Promise<string> => {
await this.getNetwork();
const blockTag = await this._ensureSafeModeBlockTagFinalization(_blockTag);
const resolved = await resolveProperties({
transaction: this._getTransactionRequest(transaction),
blockHash: this._getBlockHash(blockTag)
});
const callRequest: CallRequest = {
from: resolved.transaction.from,
to: resolved.transaction.to,
gasLimit: resolved.transaction.gasLimit?.toBigInt(),
storageLimit: undefined,
value: resolved.transaction.value?.toBigInt(),
data: resolved.transaction.data,
accessList: resolved.transaction.accessList
};
const data = resolved.blockHash
? await (this.api.rpc as any).evm.call(callRequest, resolved.blockHash)
: await (this.api.rpc as any).evm.call(callRequest);
return data.toHex();
};
Example #3
Source File: base-provider.ts From bodhi.js with Apache License 2.0 | 6 votes |
/**
* Estimate gas for a transaction.
* @param transaction The transaction to estimate the gas of
* @returns The estimated gas used by this transaction
*/
estimateGas = async (transaction: Deferrable<TransactionRequest>): Promise<BigNumber> => {
await this.call(transaction);
const { storageDepositPerByte, txFeePerGas } = this._getGasConsts();
const gasPrice = (await transaction.gasPrice) || (await this.getGasPrice());
const storageEntryLimit = BigNumber.from(gasPrice).and(0xffff);
const storageEntryDeposit = BigNumber.from(storageDepositPerByte).mul(64);
const storageGasLimit = storageEntryLimit.mul(storageEntryDeposit).div(txFeePerGas);
const resources = await this.estimateResources(transaction);
return resources.gas.add(storageGasLimit);
};
Example #4
Source File: Provider.ts From evm-provider.js with Apache License 2.0 | 6 votes |
/**
* Estimate gas for a transaction.
* @param transaction The transaction to estimate the gas of
* @returns The estimated gas used by this transaction
*/
async estimateGas(
transaction: Deferrable<TransactionRequest>
): Promise<BigNumber> {
const resources = await this.estimateResources(transaction);
return resources.gas.add(resources.storage);
}
Example #5
Source File: base-provider.ts From bodhi.js with Apache License 2.0 | 6 votes |
_getTransactionRequest = async (transaction: Deferrable<TransactionRequest>): Promise<Partial<Transaction>> => {
const values: any = await transaction;
const tx: any = {};
['from', 'to'].forEach((key) => {
if (values[key] === null || values[key] === undefined) {
return;
}
tx[key] = Promise.resolve(values[key]).then((v) => (v ? this._getAddress(v) : null));
});
['gasLimit', 'gasPrice', 'maxFeePerGas', 'maxPriorityFeePerGas', 'value'].forEach((key) => {
if (values[key] === null || values[key] === undefined) {
return;
}
tx[key] = Promise.resolve(values[key]).then((v) => (v ? BigNumber.from(v) : null));
});
['type'].forEach((key) => {
if (values[key] === null || values[key] === undefined) {
return;
}
tx[key] = Promise.resolve(values[key]).then((v) => (v !== null || v !== undefined ? v : null));
});
if (values.accessList) {
tx.accessList = accessListify(values.accessList);
}
['data'].forEach((key) => {
if (values[key] === null || values[key] === undefined) {
return;
}
tx[key] = Promise.resolve(values[key]).then((v) => (v ? hexlify(v) : null));
});
return await resolveProperties(tx);
};
Example #6
Source File: Signer.ts From evm-provider.js with Apache License 2.0 | 6 votes |
signTransaction(
transaction: Deferrable<TransactionRequest>
): Promise<string> {
return logger.throwError(
'signing transactions is unsupported',
Logger.errors.UNSUPPORTED_OPERATION,
{
operation: 'signTransaction'
}
);
}
Example #7
Source File: usePromiseTransaction.ts From useDApp with MIT License | 6 votes |
/**
* @internal
*/
export async function estimateGasLimit(
transactionRequest: TransactionRequest | undefined,
signer: Signer | undefined,
bufferGasLimitPercentage: number
) {
if (!signer || !transactionRequest) {
return undefined
}
try {
const estimatedGas = transactionRequest.gasLimit
? BigNumber.from(transactionRequest.gasLimit)
: await signer.estimateGas(transactionRequest)
return estimatedGas?.mul(bufferGasLimitPercentage + 100).div(100)
} catch (err: any) {
console.error(err)
return undefined
}
}
Example #8
Source File: Provider.ts From evm-provider.js with Apache License 2.0 | 6 votes |
async _resolveStorageLimit(
tx: Deferrable<TransactionRequest>
): Promise<BigNumber> {
if (tx.customData) {
if ('storageLimit' in tx.customData) {
const storageLimit = tx.customData.storageLimit;
if (BigNumber.isBigNumber(storageLimit)) {
return storageLimit;
} else if (isNumber(storageLimit)) {
return BigNumber.from(storageLimit);
}
}
}
// At least 60 REEF are needed to deploy
return BigNumber.from(60_000);
}
Example #9
Source File: Provider.ts From evm-provider.js with Apache License 2.0 | 6 votes |
/**
* Submit a transaction to be executed on chain.
* @param transaction The transaction to call
* @param blockTag
* @returns The call result as a hash
*/
async call(
transaction: Deferrable<TransactionRequest>,
blockTag?: BlockTag | Promise<BlockTag>
): Promise<string> {
const resolved = await this._resolveTransaction(transaction);
if (blockTag) {
const blockHash = await this._resolveBlockHash(blockTag);
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const result = await (this.api.rpc as any).evm.call(resolved, blockHash);
return result.toHex();
} else {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const result = await (this.api.rpc as any).evm.call({
to: resolved.to,
from: resolved.from,
data: resolved.data,
storageLimit: '0'
});
return result.toHex();
}
}
Example #10
Source File: transaction-manager.ts From hoprnet with GNU General Public License v3.0 | 6 votes |
/**
* Return all the queuing transactions
* @returns Array of transaction hashes
*/
public getAllQueuingTxs(): TransactionRequest[] {
// queuing tx hashes
const queuingTxHash = Array.from(this.queuing.keys())
return queuingTxHash.map((txHash) => {
const { to, data, value } = this.payloads.get(txHash)
const { nonce, maxPrority } = this.queuing.get(txHash)
return {
to,
data,
value,
nonce,
maxPrority
}
})
}
Example #11
Source File: useSendTransaction.ts From useDApp with MIT License | 5 votes |
/**
* Hook returns an object with three variables: `state`, `resetState`, and `sendTransaction`.
*
* ``state` represents the status of transaction. See {@link TransactionStatus}.
*
* `resetState` can be used to reset the state to `None` after a transaction attempt has either succeeded or failed.
*
* To send a transaction use `sendTransaction` function returned by `useSendTransaction`.
*
* Function accepts a [Transaction Request](https://docs.ethers.io/v5/api/providers/types/#providers-TransactionRequest) object as a parameter.
* @public
* @param options additional options of type {@link TransactionOptions}
* @returns {} object with two variables: `sendTransaction` and `state`: `{ sendTransaction: (...args: any[]) => void, state: TransactionStatus }`.
*
* @example
* const { sendTransaction, state } = useSendTransaction({ transactionName: 'Send Ethereum' })
*
* const handleClick = () => {
* ...
* sendTransaction({ to: address, value: utils.parseEther(amount) })
* }
*/
export function useSendTransaction(options?: TransactionOptions) {
const { library, chainId } = useEthers()
const { promiseTransaction, state, resetState } = usePromiseTransaction(chainId, options)
const { bufferGasLimitPercentage = 0 } = useConfig()
const sendTransaction = async (transactionRequest: TransactionRequest) => {
const signer = options?.signer || library?.getSigner()
if (signer) {
const gasLimit = await estimateGasLimit(transactionRequest, signer, bufferGasLimitPercentage)
await promiseTransaction(
signer.sendTransaction({
...transactionRequest,
gasLimit,
})
)
}
}
return { sendTransaction, state, resetState }
}
Example #12
Source File: Provider.ts From evm-provider.js with Apache License 2.0 | 5 votes |
/**
* Estimate resources for a transaction.
* @param transaction The transaction to estimate the resources of
* @returns The estimated resources used by this transaction
*/
async estimateResources(
transaction: Deferrable<TransactionRequest>
): Promise<{
gas: BigNumber;
storage: BigNumber;
weightFee: BigNumber;
}> {
const resolved = await this._resolveTransaction(transaction);
const from = await resolved.from;
const value = await resolved.value;
const to = await resolved.to;
const data = await resolved.data;
const storageLimit = await this._resolveStorageLimit(resolved);
if (!from) {
return logger.throwError('From cannot be undefined');
}
// construct extrinsic to estimate
const extrinsic = !to
? this.api.tx.evm.create(
data,
toBN(value),
toBN(await resolved.gasLimit),
toBN(storageLimit)
)
: this.api.tx.evm.call(
to,
data,
toBN(value),
toBN(await resolved.gasLimit),
toBN(storageLimit)
);
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const result = await (this.api.rpc as any).evm.estimateResources(
resolved.from,
extrinsic.toHex() // returns transaction bytecode?
);
return {
gas: BigNumber.from((result.gas as BN).toString()),
storage: BigNumber.from((result.storage as BN).toString()),
weightFee: BigNumber.from((result.weightFee as BN).toString())
};
}
Example #13
Source File: ethers-adapter.ts From cloud-cryptographic-wallet with MIT License | 5 votes |
async signTransaction(
deferrableTransaction: ethers.utils.Deferrable<TransactionRequest>
): Promise<string> {
const transaction = await ethers.utils.resolveProperties(
deferrableTransaction
);
const address = await this.getAddress();
if (transaction.from != null) {
if (ethers.utils.getAddress(transaction.from) !== address) {
this.logger.throwArgumentError(
"transaction from address mismatch",
"transaction.from",
transaction.from
);
}
}
const nonce = transaction.nonce
? ethers.BigNumber.from(transaction.nonce).toNumber()
: undefined;
const unsignedTransaction: ethers.utils.UnsignedTransaction = {
to: transaction.to,
nonce,
gasLimit: transaction.gasLimit,
gasPrice: transaction.gasPrice,
data: transaction.data,
value: transaction.value,
chainId: transaction.chainId,
type: transaction.type,
accessList: transaction.accessList,
maxPriorityFeePerGas: transaction.maxPriorityFeePerGas,
maxFeePerGas: transaction.maxFeePerGas,
};
(
Object.keys(unsignedTransaction) as Array<
keyof ethers.utils.UnsignedTransaction
>
).forEach((key) => {
if (key in unsignedTransaction && unsignedTransaction[key] == undefined) {
delete unsignedTransaction[key];
}
});
const hash = ethers.utils.keccak256(
ethers.utils.serializeTransaction(unsignedTransaction)
);
const signature = await this.config.signer.sign(Bytes.fromString(hash));
const ethersSignature = ethers.utils.splitSignature({
v: signature.v,
r: signature.r.toString(),
s: signature.s.toString(),
});
return ethers.utils.serializeTransaction(
unsignedTransaction,
ethersSignature
);
}
Example #14
Source File: kms-ethers-signer.ts From cloud-cryptographic-wallet with MIT License | 5 votes |
async signTransaction(
deferrableTransaction: Deferrable<TransactionRequest>
): Promise<string> {
return this.adapter.signTransaction(deferrableTransaction);
}
Example #15
Source File: adapter.ts From cloud-cryptographic-wallet with MIT License | 5 votes |
async signTransaction(
deferrableTransaction: Deferrable<TransactionRequest>
): Promise<string> {
const transaction = await resolveProperties(deferrableTransaction);
const address = await this.getAddress();
if (transaction.from != null) {
if (getAddress(transaction.from) !== address) {
this.logger.throwArgumentError(
"transaction from address mismatch",
"transaction.from",
transaction.from
);
}
}
const nonce = transaction.nonce
? BigNumber.from(transaction.nonce).toNumber()
: undefined;
const unsignedTransaction: UnsignedTransaction = {
to: transaction.to,
nonce,
gasLimit: transaction.gasLimit,
gasPrice: transaction.gasPrice,
data: transaction.data,
value: transaction.value,
chainId: transaction.chainId,
type: transaction.type,
accessList: transaction.accessList,
maxPriorityFeePerGas: transaction.maxPriorityFeePerGas,
maxFeePerGas: transaction.maxFeePerGas,
};
(
Object.keys(unsignedTransaction) as Array<keyof UnsignedTransaction>
).forEach((key) => {
if (key in unsignedTransaction && unsignedTransaction[key] == undefined) {
delete unsignedTransaction[key];
}
});
const digest = keccak256(serialize(unsignedTransaction));
const signature = await this.signer.sign(
Buffer.from(digest.slice(2), "hex")
);
const ethersSignature = splitSignature({
v: signature.v,
r: `0x${signature.r.toString("hex")}`,
s: `0x${signature.s.toString("hex")}`,
});
return serialize(unsignedTransaction, ethersSignature);
}
Example #16
Source File: recoverFunds.ts From aavegotchi-contracts with MIT License | 5 votes |
async function main() {
//@ts-ignore
const accounts = await ethers.getSigners();
let signer: Signer = accounts[0];
await network.provider.request({
method: "hardhat_impersonateAccount",
params: [aavegotchi],
});
signer = await ethers.provider.getSigner(aavegotchi);
for (let index = 0; index < 30; index++) {
let nonce = await signer.getTransactionCount();
console.log("nonce:", nonce.toString());
const tx: TransactionRequest = {
data: deployData,
};
const result = await signer.sendTransaction(tx);
//@ts-ignore
if (result.creates === contractAddress) {
//@ts-ignore
console.log("result:", result.creates);
nonce = await signer.getTransactionCount();
console.log("nonce:", nonce.toString());
let bpt = await ethers.getContractAt(
"ERC20Token",
"0x0ec9f76202a7061eb9b3a7d6b59d36215a7e37da"
);
bpt = await impersonate(contractAddress, bpt, ethers, network);
let bal = await bpt.balanceOf(contractAddress);
console.log("bal:", bal.toString());
await bpt.transfer(aavegotchi, bal);
bal = await bpt.balanceOf(contractAddress);
console.log("bal:", bal.toString());
throw new Error(`Yesss it worked, nonce is: ${nonce}!`);
}
}
}
Example #17
Source File: base-provider.ts From bodhi.js with Apache License 2.0 | 5 votes |
/**
* Estimate resources for a transaction.
* @param transaction The transaction to estimate the resources of
* @returns The estimated resources used by this transaction
*/
estimateResources = async (
transaction: Deferrable<TransactionRequest>
): Promise<{
gas: BigNumber;
storage: BigNumber;
weightFee: BigNumber;
}> => {
const ethTx = await this._getTransactionRequest(transaction);
const { from, to, data, value } = ethTx;
const accessList = ethTx.accessList?.map(({ address, storageKeys }) => [address, storageKeys]) || [];
const extrinsic = !to
? this.api.tx.evm.create(
data!,
value?.toBigInt()!,
U64MAX.toBigInt(), // gas_limit u64::max
U32MAX.toBigInt(), // storage_limit u32::max
// @ts-ignore @TODO fix type
accessList
)
: this.api.tx.evm.call(
to,
data!,
value?.toBigInt()!,
U64MAX.toBigInt(), // gas_limit u64::max
U32MAX.toBigInt(), // storage_limit u32::max
// @ts-ignore @TODO fix type
accessList
);
const result = await (this.api.rpc as any).evm.estimateResources(from, extrinsic.toHex());
return {
gas: BigNumber.from((result.gas as BN).toString()),
storage: BigNumber.from((result.storage as BN).toString()),
weightFee: BigNumber.from((result.weightFee as BN).toString())
};
};
Example #18
Source File: base-provider.ts From bodhi.js with Apache License 2.0 | 5 votes |
/**
* Get the gas for eth transactions
* @returns The gas used by eth transaction
*/
getEthResources = async (
transaction: Deferrable<TransactionRequest>,
{
gasLimit,
storageLimit,
validUntil
}: {
gasLimit?: BigNumberish;
storageLimit?: BigNumberish;
validUntil?: BigNumberish;
} = {}
): Promise<{
gasPrice: BigNumber;
gasLimit: BigNumber;
}> => {
if (!gasLimit || !storageLimit) {
const { gas, storage } = await this.estimateResources(transaction);
gasLimit = gasLimit ?? gas;
storageLimit = storageLimit ?? storage;
}
if (!validUntil) {
const blockNumber = await this.getBlockNumber();
// Expires after 100 blocks by default
validUntil = blockNumber + 100;
}
const storageByteDeposit = (this.api.consts.evm.storageDepositPerByte as UInt).toBigInt();
const txFeePerGas = (this.api.consts.evm.txFeePerGas as UInt).toBigInt();
const { txGasLimit, txGasPrice } = calcEthereumTransactionParams({
gasLimit,
storageLimit,
validUntil,
storageByteDeposit,
txFeePerGas
});
return {
gasLimit: txGasLimit,
gasPrice: txGasPrice
};
};
Example #19
Source File: Signer.ts From bodhi.js with Apache License 2.0 | 5 votes |
signTransaction(transaction: Deferrable<TransactionRequest>): Promise<string> {
return logger.throwError('signing transactions is unsupported', Logger.errors.UNSUPPORTED_OPERATION, {
operation: 'signTransaction'
});
}
Example #20
Source File: Signer.ts From evm-provider.js with Apache License 2.0 | 4 votes |
/**
*
* @param transaction
* @returns A promise that resolves to the transaction's response
*/
async sendTransaction(
_transaction: Deferrable<TransactionRequest>
): Promise<TransactionResponse> {
this._checkProvider('sendTransaction');
const signerAddress = await this.getSubstrateAddress();
const evmAddress = await this.getAddress();
// estimateResources requires the from parameter.
// However, when creating the contract, there is no from parameter in the tx
const transaction = {
from: evmAddress,
..._transaction
};
const resources = await this.provider.estimateResources(transaction);
// Multiply by 3.1
const gasLimit: BigNumber = resources.gas.mul(31).div(10);
let storageLimit: BigNumber;
// If the storage limit is supplied, override it from the estimateResources
if (transaction.customData) {
if ('storageLimit' in transaction.customData) {
storageLimit = transaction.customData.storageLimit;
if (isNumber(storageLimit)) {
storageLimit = BigNumber.from(storageLimit);
}
}
} else {
storageLimit = resources.storage.mul(31).div(10);
}
let totalLimit = await transaction.gasLimit;
if (totalLimit === null || totalLimit === undefined) {
totalLimit = gasLimit.add(storageLimit);
}
transaction.gasLimit = totalLimit;
const tx = await this.populateTransaction(transaction);
const data = tx.data;
const from = tx.from;
if (!data) {
return logger.throwError('Request data not found');
}
if (!from) {
return logger.throwError('Request from not found');
}
let extrinsic: SubmittableExtrinsic<'promise'>;
// @TODO create contract
if (!tx.to) {
extrinsic = this.provider.api.tx.evm.create(
tx.data,
toBN(tx.value),
toBN(gasLimit),
toBN(storageLimit.isNegative() ? 0 : storageLimit)
);
} else {
extrinsic = this.provider.api.tx.evm.call(
tx.to,
tx.data,
toBN(tx.value),
toBN(gasLimit),
toBN(storageLimit.isNegative() ? 0 : storageLimit)
);
}
await extrinsic.signAsync(signerAddress);
return new Promise((resolve, reject) => {
extrinsic
.send((result: SubmittableResult) => {
handleTxResponse(result, this.provider.api)
.then(() => {
resolve({
hash: extrinsic.hash.toHex(),
from: from || '',
confirmations: 0,
nonce: toBN(tx.nonce).toNumber(),
gasLimit: BigNumber.from(tx.gasLimit || '0'),
gasPrice: BigNumber.from(0),
data: dataToString(data),
value: BigNumber.from(tx.value || '0'),
chainId: 13939,
wait: (confirmations?: number): Promise<TransactionReceipt> => {
return this.provider._resolveTransactionReceipt(
extrinsic.hash.toHex(),
result.status.asInBlock.toHex(),
from
);
}
});
})
.catch(({ message, result }) => {
reject(message);
});
})
.catch((error) => {
reject(error && error.message);
});
});
}
Example #21
Source File: useRawLogs.test.ts From useDApp with MIT License | 4 votes |
describe('useRawLogs', () => {
const mockProvider = new MockProvider()
const secondMockProvider = new MockProvider({ ganacheOptions: { _chainIdRpc: SECOND_TEST_CHAIN_ID } as any })
const [deployer, receiver] = mockProvider.getWallets()
const [secondDeployer] = secondMockProvider.getWallets()
const eventTopic = ethers.utils.id('Transfer(address,address,uint256)')
let token: Contract
let secondToken: Contract
beforeEach(async () => {
token = await deployMockToken(deployer)
secondToken = await deployMockToken(secondDeployer, SECOND_MOCK_TOKEN_INITIAL_BALANCE)
})
async function sendToken(signer: ethers.Wallet, to: string, amount: BigNumber) {
const { result, waitForCurrent, waitForNextUpdate } = await renderWeb3Hook(
() =>
useSendTransaction({
signer,
}),
{ mockProvider }
)
await waitForNextUpdate()
const txData = ERC20MockInterface.encodeFunctionData('transfer(address,uint)', [to, amount])
const tx: TransactionRequest = {
to: token.address,
value: BigNumber.from(0),
data: txData,
gasPrice: 0,
}
await result.current.sendTransaction(tx)
await waitForCurrent((val) => val.state !== undefined)
expect(result.current.state.status).to.eq('Success')
}
function extractAddress(address: string) {
let result: string
result = hexStripZeros(address)
while (result.length != 42) result = '0x0' + result.substring(2)
return result
}
it('Can get only the recent token transfer log', async () => {
const blockNumber = await mockProvider.getBlockNumber()
const from = deployer
const to = receiver
const fromAddress = from.address
const toAddress = to.address
const amount = BigNumber.from(1)
await sendToken(from, toAddress, amount)
const filter: Filter = {
address: token.address,
fromBlock: blockNumber + 1,
toBlock: blockNumber + 2,
topics: [eventTopic],
}
const { result, waitForCurrent } = await renderWeb3Hook(() => useRawLogs(filter), { mockProvider })
await waitForCurrent((val) => val !== undefined)
expect(result.error).to.be.undefined
expect(result.current?.length).to.equal(1, 'Number of logs')
const log = result.current![0]
expect(log.topics[0]).to.equal(eventTopic, 'Event topic')
expect(getAddress(extractAddress(log.topics[1]))).to.equal(getAddress(fromAddress), 'From')
expect(getAddress(extractAddress(log.topics[2]))).to.equal(getAddress(toAddress), 'To')
const decodedData = defaultAbiCoder.decode(['uint'], log.data)
expect(decodedData[0]).to.equal(amount, 'Amount')
})
it('Can get all token transfer logs', async () => {
const from = deployer
const to = receiver
const fromAddress = from.address
const toAddress = to.address
const amount = BigNumber.from(1)
await sendToken(from, toAddress, amount)
const filter: Filter = {
address: token.address,
fromBlock: 0,
toBlock: 'latest',
topics: [eventTopic],
}
const { result, waitForCurrent } = await renderWeb3Hook(() => useRawLogs(filter), { mockProvider })
await waitForCurrent((val) => val !== undefined)
expect(result.error).to.be.undefined
expect(result.current?.length).to.equal(2, 'Number of logs')
// Mint transfer event
const log1 = result.current![0]
expect(log1.topics[0]).to.equal(eventTopic, 'Event topic')
expect(getAddress(extractAddress(log1.topics[1]))).to.equal(getAddress(AddressZero), 'From')
expect(getAddress(extractAddress(log1.topics[2]))).to.equal(getAddress(deployer.address), 'To')
const decodedData1 = defaultAbiCoder.decode(['uint'], log1.data)
expect(decodedData1[0]).to.equal(MOCK_TOKEN_INITIAL_BALANCE, 'Amount')
// Recent transfer transaction log
const log = result.current![1]
expect(log.topics[0]).to.equal(eventTopic, 'Event topic')
expect(getAddress(extractAddress(log.topics[1]))).to.equal(getAddress(fromAddress), 'From')
expect(getAddress(extractAddress(log.topics[2]))).to.equal(getAddress(toAddress), 'To')
const decodedData = defaultAbiCoder.decode(['uint'], log.data)
expect(decodedData[0]).to.equal(amount, 'Amount')
})
it('Can get the mint transfer log', async () => {
const filter: Filter = {
address: token.address,
fromBlock: 0,
toBlock: 'latest',
topics: [eventTopic],
}
const { result, waitForCurrent } = await renderWeb3Hook(() => useRawLogs(filter), { mockProvider })
await waitForCurrent((val) => val !== undefined)
expect(result.error).to.be.undefined
expect(result.current?.length).to.equal(1, 'Number of logs')
const log = result.current![0]
expect(log.topics[0]).to.equal(eventTopic, 'Event topic')
expect(getAddress(extractAddress(log.topics[1]))).to.equal(getAddress(AddressZero), 'From')
expect(getAddress(extractAddress(log.topics[2]))).to.equal(getAddress(deployer.address), 'To')
const decodedData = defaultAbiCoder.decode(['uint'], log.data)
expect(decodedData[0]).to.equal(MOCK_TOKEN_INITIAL_BALANCE, 'Amount')
})
it('Can get the mint transfer log on the alternative chain', async () => {
const filter: Filter = {
address: secondToken.address,
fromBlock: 0,
toBlock: 'latest',
topics: [eventTopic],
}
const { result, waitForCurrent } = await renderWeb3Hook(() => useRawLogs(filter), {
mockProvider: secondMockProvider,
})
await waitForCurrent((val) => val !== undefined)
expect(result.error).to.be.undefined
expect(result.current?.length).to.equal(1, 'Number of logs')
const log = result.current![0]
expect(log.topics[0]).to.equal(eventTopic, 'Event topic')
expect(getAddress(extractAddress(log.topics[1]))).to.equal(getAddress(AddressZero), 'From')
expect(getAddress(extractAddress(log.topics[2]))).to.equal(getAddress(secondDeployer.address), 'To')
const decodedData = defaultAbiCoder.decode(['uint'], log.data)
expect(decodedData[0]).to.equal(SECOND_MOCK_TOKEN_INITIAL_BALANCE, 'Amount')
})
it('Works if there are no logs', async () => {
const filter: Filter = {
address: secondToken.address, // Token on the other chain... doesn't exist so there should be no logs
fromBlock: 0,
toBlock: 'latest',
topics: [eventTopic],
}
const { result, waitForCurrent } = await renderWeb3Hook(() => useRawLogs(filter), { mockProvider })
await waitForCurrent((val) => val !== undefined)
expect(result.error).to.be.undefined
expect(result.current?.length).to.equal(0, 'Number of logs')
})
})
Example #22
Source File: useLogs.test.tsx From useDApp with MIT License | 4 votes |
describe('useLogs', () => {
const mockProvider = new MockProvider()
const secondMockProvider = new MockProvider({ ganacheOptions: { _chainIdRpc: SECOND_TEST_CHAIN_ID } as any })
const [deployer, receiver] = mockProvider.getWallets()
const [secondDeployer] = secondMockProvider.getWallets()
let token: Contract
let secondToken: Contract
beforeEach(async () => {
token = await deployMockToken(deployer)
secondToken = await deployMockToken(secondDeployer, SECOND_MOCK_TOKEN_INITIAL_BALANCE)
})
async function sendToken(signer: ethers.Wallet, to: string, amount: BigNumber) {
const { result, waitForCurrent, waitForNextUpdate } = await renderWeb3Hook(
() =>
useSendTransaction({
signer,
}),
{ mockProvider }
)
await waitForNextUpdate()
const txData = ERC20MockInterface.encodeFunctionData('transfer(address,uint)', [to, amount])
const tx: TransactionRequest = {
to: token.address,
value: BigNumber.from(0),
data: txData,
gasPrice: 0,
}
await result.current.sendTransaction(tx)
await waitForCurrent((val) => val.state !== undefined)
expect(result.current.state.status).to.eq('Success')
return result.current.state
}
it('Can get only the recent token transfer log', async () => {
const blockNumber = await mockProvider.getBlockNumber()
const from = deployer
const to = receiver
const fromAddress = from.address
const toAddress = to.address
const amount = BigNumber.from(1)
await sendToken(from, toAddress, amount)
const { result, waitForCurrent } = await renderWeb3Hook(
() =>
useLogs(
{
contract: token,
event: 'Transfer',
args: [],
},
{
fromBlock: blockNumber + 1,
toBlock: blockNumber + 2,
}
),
{ mockProvider }
)
await waitForCurrent((val) => val !== undefined)
expect(result.error).to.be.undefined
expect(result.current?.value).to.not.be.undefined
expect(result.current?.error).to.be.undefined
expect(result.current?.value?.length).to.equal(1, 'Number of logs')
const log = result.current!.value![0]
expect(getAddress(log.data['from'])).to.equal(getAddress(fromAddress), 'From')
expect(getAddress(log.data['to'])).to.equal(getAddress(toAddress), 'To')
expect(log.data['value']).to.equal(amount, 'Amount')
})
it('Can get all token transfer logs using the default log query parameters', async () => {
const from = deployer
const to = receiver
const fromAddress = from.address
const toAddress = to.address
const amount = BigNumber.from(1)
await sendToken(from, toAddress, amount)
const { result, waitForCurrent } = await renderWeb3Hook(
() =>
useLogs({
contract: token,
event: 'Transfer',
args: [],
}),
{ mockProvider }
)
await waitForCurrent((val) => val !== undefined)
expect(result.error).to.be.undefined
expect(result.current?.value).to.not.be.undefined
expect(result.current?.error).to.be.undefined
expect(result.current?.value?.length).to.equal(2, 'Number of logs')
// Mint transfer event
const log1 = result.current!.value![0]
expect(getAddress(log1.data['from'])).to.equal(getAddress(AddressZero), 'From')
expect(getAddress(log1.data['to'])).to.equal(getAddress(deployer.address), 'To')
expect(log1.data['value']).to.equal(MOCK_TOKEN_INITIAL_BALANCE, 'Amount')
// Recent transfer transaction log
const log = result.current!.value![1]
expect(getAddress(log.data['from'])).to.equal(getAddress(fromAddress), 'From')
expect(getAddress(log.data['to'])).to.equal(getAddress(toAddress), 'To')
expect(log.data['value']).to.equal(amount, 'Amount')
})
it('Can get the mint transfer log', async () => {
const { result, waitForCurrent } = await renderWeb3Hook(
() =>
useLogs(
{
contract: token,
event: 'Transfer',
args: [],
},
{
fromBlock: 0,
toBlock: 'latest',
}
),
{ mockProvider }
)
await waitForCurrent((val) => val !== undefined)
expect(result.error).to.be.undefined
expect(result.current?.value).to.not.be.undefined
expect(result.current?.error).to.be.undefined
expect(result.current?.value?.length).to.equal(1, 'Number of logs')
const log = result.current!.value![0]
expect(getAddress(log.data['from'])).to.equal(getAddress(AddressZero), 'From')
expect(getAddress(log.data['to'])).to.equal(getAddress(deployer.address), 'To')
expect(log.data['value']).to.equal(MOCK_TOKEN_INITIAL_BALANCE, 'Amount')
})
it('Can get the mint transfer log on the alternative chain', async () => {
const { result, waitForCurrent } = await renderWeb3Hook(
() =>
useLogs(
{
contract: secondToken,
event: 'Transfer',
args: [],
},
{
fromBlock: 0,
toBlock: 'latest',
}
),
{
mockProvider: secondMockProvider,
}
)
await waitForCurrent((val) => val !== undefined)
expect(result.error).to.be.undefined
expect(result.current?.value).to.not.be.undefined
expect(result.current?.error).to.be.undefined
expect(result.current?.value?.length).to.equal(1, 'Number of logs')
const log = result.current!.value![0]
expect(getAddress(log.data['from'])).to.equal(getAddress(AddressZero), 'From')
expect(getAddress(log.data['to'])).to.equal(getAddress(secondDeployer.address), 'To')
expect(log.data['value']).to.equal(SECOND_MOCK_TOKEN_INITIAL_BALANCE, 'Amount')
})
it('Works if there are no logs', async () => {
const { result, waitForCurrent } = await renderWeb3Hook(
() =>
useLogs(
{
contract: secondToken, // Token on the other chain... doesn't exist so there should be no logs
event: 'Transfer',
args: [],
},
{
fromBlock: 0,
toBlock: 'latest',
}
),
{ mockProvider }
)
await waitForCurrent((val) => val !== undefined)
expect(result.error).to.be.undefined
expect(result.current?.value).to.not.be.undefined
expect(result.current?.error).to.be.undefined
expect(result.current?.value?.length).to.equal(0, 'Number of logs')
})
it('Can query mint transfer logs by sender', async () => {
// Send to emit another Transfer token that our filter should filter out
await sendToken(deployer, receiver.address, BigNumber.from(1))
const { result, waitForCurrent } = await renderWeb3Hook(
() =>
useLogs(
{
contract: token,
event: 'Transfer',
args: [AddressZero],
},
{
fromBlock: 0,
toBlock: 'latest',
}
),
{ mockProvider }
)
await waitForCurrent((val) => val !== undefined)
expect(result.error).to.be.undefined
expect(result.current?.value).to.not.be.undefined
expect(result.current?.error).to.be.undefined
expect(result.current?.value?.length).to.equal(1, 'Number of logs')
const log = result.current!.value![0]
expect(getAddress(log.data['from'])).to.equal(getAddress(AddressZero), 'From')
expect(getAddress(log.data['to'])).to.equal(getAddress(deployer.address), 'To')
expect(log.data['value']).to.equal(MOCK_TOKEN_INITIAL_BALANCE, 'Amount')
})
it('Can query mint transfer logs by receiver', async () => {
// Send to emit another Transfer token that our filter should filter out
await sendToken(deployer, receiver.address, BigNumber.from(1))
const { result, waitForCurrent } = await renderWeb3Hook(
() =>
useLogs(
{
contract: token,
event: 'Transfer',
args: [null, deployer.address],
},
{
fromBlock: 0,
toBlock: 'latest',
}
),
{ mockProvider }
)
await waitForCurrent((val) => val !== undefined)
expect(result.error).to.be.undefined
expect(result.current?.value).to.not.be.undefined
expect(result.current?.error).to.be.undefined
expect(result.current?.value?.length).to.equal(1, 'Number of logs')
const log = result.current!.value![0]
expect(getAddress(log.data['from'])).to.equal(getAddress(AddressZero), 'From')
expect(getAddress(log.data['to'])).to.equal(getAddress(deployer.address), 'To')
expect(log.data['value']).to.equal(MOCK_TOKEN_INITIAL_BALANCE, 'Amount')
})
it('We get an error when we query by un-indexed values', async () => {
// Send to emit another Transfer token that our filter should filter out
await sendToken(deployer, receiver.address, BigNumber.from(1))
const { result, waitForCurrent } = await renderWeb3Hook(
() =>
useLogs(
{
contract: token,
event: 'Transfer',
args: [null, null, MOCK_TOKEN_INITIAL_BALANCE],
},
{
fromBlock: 0,
toBlock: 'latest',
}
),
{ mockProvider }
)
await waitForCurrent((val) => val !== undefined)
expect(result.error).to.be.undefined
expect(result.current?.value).to.be.undefined
expect(result.current?.error).to.not.be.undefined
})
it('Can query by block hash', async () => {
// Send to emit another Transfer token that our filter should filter out
const { receipt } = await sendToken(deployer, receiver.address, BigNumber.from(1))
const { result, waitForCurrent } = await renderWeb3Hook(
() =>
useLogs(
{
contract: token,
event: 'Transfer',
args: [],
},
{
blockHash: receipt?.blockHash,
}
),
{ mockProvider }
)
await waitForCurrent((val) => val !== undefined)
expect(result.error).to.be.undefined
expect(result.current?.value).to.not.be.undefined
expect(result.current?.error).to.be.undefined
expect(result.current?.value?.length).to.equal(1, 'Number of logs')
const log = result.current!.value![0]
expect(getAddress(log.data['from'])).to.equal(getAddress(deployer.address), 'From')
expect(getAddress(log.data['to'])).to.equal(getAddress(receiver.address), 'To')
expect(log.data['value']).to.equal(BigNumber.from(1), 'Amount')
expect(log.blockHash).to.equal(receipt?.blockHash, 'Block hash')
expect(log.blockNumber).to.equal(receipt?.blockNumber, 'Block number')
expect(log.transactionHash).to.equal(receipt?.transactionHash, 'Transaction hash')
expect(log.transactionIndex).to.equal(receipt?.transactionIndex, 'Transaction index')
})
})
Example #23
Source File: Signer.ts From bodhi.js with Apache License 2.0 | 4 votes |
/**
*
* @param transaction
* @returns A promise that resolves to the transaction's response
*/
async sendTransaction(_transaction: Deferrable<TransactionRequest>): Promise<TransactionResponse> {
this._checkProvider('sendTransaction');
const signerAddress = await this.getSubstrateAddress();
const evmAddress = await this.getAddress();
// estimateResources requires the from parameter.
// However, when creating the contract, there is no from parameter in the tx
const transaction = {
from: evmAddress,
..._transaction
};
const resources = await this.provider.estimateResources(transaction);
let gasLimit: BigNumber;
let storageLimit: BigNumber;
let totalLimit = await transaction.gasLimit;
if (totalLimit === null || totalLimit === undefined) {
gasLimit = resources.gas;
storageLimit = resources.storage;
totalLimit = resources.gas.add(resources.storage);
} else {
const estimateTotalLimit = resources.gas.add(resources.storage);
gasLimit = BigNumber.from(totalLimit).mul(resources.gas).div(estimateTotalLimit).add(1);
storageLimit = BigNumber.from(totalLimit).mul(resources.storage).div(estimateTotalLimit).add(1);
}
transaction.gasLimit = totalLimit;
const tx = await this.populateTransaction(transaction);
const data = tx.data;
const from = tx.from;
if (!data) {
return logger.throwError('Request data not found');
}
if (!from) {
return logger.throwError('Request from not found');
}
let extrinsic: SubmittableExtrinsic<'promise'>;
// @TODO create contract
if (!tx.to) {
extrinsic = this.provider.api.tx.evm.create(
tx.data,
toBN(tx.value),
toBN(gasLimit),
toBN(storageLimit.isNegative() ? 0 : storageLimit),
tx.accessList || []
);
} else {
extrinsic = this.provider.api.tx.evm.call(
tx.to,
tx.data,
toBN(tx.value),
toBN(gasLimit),
toBN(storageLimit.isNegative() ? 0 : storageLimit),
tx.accessList || []
);
}
await extrinsic.signAsync(signerAddress);
return new Promise((resolve, reject) => {
extrinsic
.send((result: SubmittableResult) => {
handleTxResponse(result, this.provider.api)
.then(() => {
resolve({
hash: extrinsic.hash.toHex(),
from: from || '',
confirmations: 0,
nonce: toBN(tx.nonce).toNumber(),
gasLimit: BigNumber.from(tx.gasLimit || '0'),
gasPrice: BigNumber.from(1),
data: dataToString(data),
value: BigNumber.from(tx.value || '0'),
chainId: +this.provider.api.consts.evmAccounts.chainId.toString(),
wait: (confirmations?: number): Promise<TransactionReceipt> => {
const hex = result.status.isInBlock
? result.status.asInBlock.toHex()
: result.status.asFinalized.toHex();
return this.provider.getTransactionReceiptAtBlock(extrinsic.hash.toHex(), hex);
}
});
})
.catch(reject);
})
.catch(reject);
});
}