Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

new transaction #167

Merged
merged 7 commits into from
Dec 3, 2021
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 19 additions & 6 deletions eth-providers/src/__tests__/e2e/tx.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { createTestPairs } from '@polkadot/keyring/testingPairs';
import type { KeyringPair } from '@polkadot/keyring/types';
import { expect } from 'chai';
import { EvmRpcProvider } from '../../rpc-provider';
import { sendTx } from '../../utils';
import { sendTx, calcEthereumTransactionParams } from '../../utils';
import { computeDefaultSubstrateAddress } from '../../utils/address';
import evmAccounts from '../evmAccounts';
import {
Expand All @@ -17,6 +17,7 @@ import {
createTransactionPayload,
signTransaction
} from '@acala-network/eth-transactions';
import type { UInt } from '@polkadot/types';

it('a series of tests', async () => {
console.log('test start');
Expand All @@ -26,6 +27,8 @@ it('a series of tests', async () => {

const provider = EvmRpcProvider.from(endpoint);
const chainId = await provider.chainId();
const storageByteDeposit = (provider.api.consts.evm.storageDepositPerByte as UInt).toBigInt();
const txFeePerGas = (provider.api.consts.evm.txFeePerGas as UInt).toBigInt();

const account1Wallet = new Wallet(account1.privateKey).connect(provider as any);

Expand Down Expand Up @@ -60,11 +63,22 @@ it('a series of tests', async () => {

/** serializeTransaction legacyRawTx */
console.log('serializeTransaction legacy');

const { txGasLimit, txGasPrice } = calcEthereumTransactionParams({
gasLimit: 2100001n,
validUntil: 3601n,
storageLimit: 64001n,
txFeePerGas,
storageByteDeposit
});

console.log(txFeePerGas, storageByteDeposit);

const unsignTx: Eip712Transaction = {
nonce: await provider.getTransactionCount(account1Wallet.address),
chainId,
gasLimit: BigNumber.from('0x030dcf'),
gasPrice: BigNumber.from('0x0186a000002710'),
gasLimit: txGasLimit,
gasPrice: txGasPrice,
data: deployHelloWorldData,
value: BigNumber.from(0)
};
Expand All @@ -89,8 +103,8 @@ it('a series of tests', async () => {
const walletSendTransaction = async () => {
console.log('wallet sendTransaction');
await account1Wallet.sendTransaction({
gasLimit: BigNumber.from('0x030dcf'),
gasPrice: BigNumber.from('0x0186a000002710'),
gasLimit: txGasLimit,
gasPrice: txGasPrice,
data: deployHelloWorldData,
type: 0
});
Expand All @@ -100,7 +114,6 @@ it('a series of tests', async () => {

/** serializeTransaction eip712 */
console.log('serializeTransaction eip712');
console.log('nonce', await provider.getTransactionCount(account1Wallet.address));
const unsignEip712Tx: Eip712Transaction = {
nonce: await provider.getTransactionCount(account1Wallet.address),
chainId,
Expand Down
47 changes: 47 additions & 0 deletions eth-providers/src/__tests__/transactionHelper.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import ACAABI from '@acala-network/contracts/build/contracts/Token.json';
import ADDRESS from '@acala-network/contracts/utils/Address';
import { BigNumber } from '@ethersproject/bignumber';
import { Contract } from '@ethersproject/contracts';
import { Wallet } from '@ethersproject/wallet';
import { createTestPairs } from '@polkadot/keyring/testingPairs';
import type { KeyringPair } from '@polkadot/keyring/types';
import { expect } from 'chai';
import { EvmRpcProvider } from '../rpc-provider';
import { sendTx, calcEthereumTransactionParams, calcSubstrateTransactionParams } from '../utils';
import { computeDefaultSubstrateAddress } from '../utils/address';
import evmAccounts from './evmAccounts';
import {
serializeTransaction,
Eip712Transaction,
parseTransaction,
createTransactionPayload,
signTransaction
} from '@acala-network/eth-transactions';
import type { UInt } from '@polkadot/types';

it('transactionHelper', async () => {
const txFeePerGas = 199999946752n;
const storageByteDeposit = 100000000000000n;

const ethParams = calcEthereumTransactionParams({
gasLimit: 2100001n,
validUntil: 3601n,
storageLimit: 64001n,
txFeePerGas,
storageByteDeposit
});

expect(ethParams.txGasPrice.toBigInt()).equal(200007812072n);
expect(ethParams.txGasLimit.toBigInt()).equal(34100001n);

const subParams = calcSubstrateTransactionParams({
txGasLimit: ethParams.txGasLimit,
txGasPrice: ethParams.txGasPrice,
txFeePerGas,
storageByteDeposit
});

expect(subParams.gasLimit.toBigInt()).equal(2100001n);
expect(subParams.storageLimit.toBigInt()).equal(64000n);
expect(subParams.validUntil.toBigInt()).equal(3600n);
});
30 changes: 21 additions & 9 deletions eth-providers/src/base-provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import { accessListify, Transaction } from '@ethersproject/transactions';
import { ApiPromise } from '@polkadot/api';
import { createHeaderExtended } from '@polkadot/api-derive';
import { SubmittableExtrinsic } from '@polkadot/api/types';
import type { GenericExtrinsic, Option } from '@polkadot/types';
import type { GenericExtrinsic, Option, UInt } from '@polkadot/types';
import type { AccountId, Header } from '@polkadot/types/interfaces';
import type BN from 'bn.js';
import { BigNumber, BigNumberish } from 'ethers';
Expand All @@ -47,7 +47,8 @@ import {
logger,
PROVIDER_ERRORS,
sendTx,
throwNotImplemented
throwNotImplemented,
calcSubstrateTransactionParams
} from './utils';
import { TransactionReceipt as TransactionReceiptGQL } from './utils/gqlTypes';
import { UnfinalizedBlockCache } from './utils/unfinalizedBlockCache';
Expand Down Expand Up @@ -612,8 +613,9 @@ export abstract class BaseProvider extends AbstractProvider {
return logger.throwArgumentError('missing from address', 'transaction', ethTx);
}

let storageLimit = '0';
let validUntil = '0';
let storageLimit = 0n;
let validUntil = 0n;
let gasLimit = 0n;

if (ethTx.type === 96) {
// eip712
Expand All @@ -625,12 +627,22 @@ export abstract class BaseProvider extends AbstractProvider {
if (!_validUntil) {
return logger.throwError('expect validUntil');
}
storageLimit = _storageLimit;
validUntil = _validUntil;

gasLimit = ethTx.gasLimit.toBigInt();
storageLimit = BigInt(_storageLimit);
validUntil = BigInt(_validUntil);
} else if (ethTx.type == null || ethTx.type === 0) {
// Legacy and EIP-155 Transactions
storageLimit = ethTx.gasPrice?.shr(32).toString() ?? '0';
validUntil = ethTx.gasPrice?.and(0xffffffff).toString() ?? '0';
const params = calcSubstrateTransactionParams({
txGasPrice: ethTx.gasPrice || '0',
txGasLimit: ethTx.gasLimit || '0',
storageByteDeposit: (this.api.consts.evm.storageDepositPerByte as UInt).toBigInt(),
txFeePerGas: (this.api.consts.evm.txFeePerGas as UInt).toBigInt()
});

gasLimit = params.gasLimit.toBigInt();
validUntil = params.validUntil.toBigInt();
storageLimit = params.storageLimit.toBigInt();
} else if (ethTx.type === 1) {
// EIP-2930
return throwNotImplemented('EIP-2930 transactions');
Expand All @@ -643,7 +655,7 @@ export abstract class BaseProvider extends AbstractProvider {
ethTx.to ? { Call: ethTx.to } : { Create: null },
ethTx.data,
ethTx.value.toString(),
ethTx.gasLimit.toString(),
gasLimit,
storageLimit,
validUntil
);
Expand Down
1 change: 1 addition & 0 deletions eth-providers/src/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ export * from './getPartialTransactionReceipt';
export * from './queries';
export * from './handleTxResponse';
export * from './sendTx';
export * from './transactionHelper';
69 changes: 69 additions & 0 deletions eth-providers/src/utils/transactionHelper.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import { BigNumber, BigNumberish } from 'ethers';

type TxConsts = {
storageByteDeposit: BigNumberish;
txFeePerGas: BigNumberish;
};

const bigNumDiv = (x: BigNumber, y: BigNumber) => {
const res = x.div(y);
return res.mul(y) === x ? res : res.add(1);
};

export const calcEthereumTransactionParams = (
data: {
gasLimit: BigNumberish;
storageLimit: BigNumberish;
validUntil: BigNumberish;
} & TxConsts
): {
txGasPrice: BigNumber;
txGasLimit: BigNumber;
} => {
const gasLimit = BigNumber.from(data.gasLimit);
const storageLimit = BigNumber.from(data.storageLimit);
const validUntil = BigNumber.from(data.validUntil);
const storageByteDeposit = BigNumber.from(data.storageByteDeposit);
const txFeePerGas = BigNumber.from(data.txFeePerGas);

const blockPeriod = validUntil.div(30);
const storageEntryLimit = storageLimit.div(64);
ntduan marked this conversation as resolved.
Show resolved Hide resolved
const storageEntryDeposit = storageByteDeposit.mul(64);
const txGasPrice = txFeePerGas.add(blockPeriod.shl(16)).add(storageEntryLimit);

const txGasLimit = storageEntryDeposit.div(txFeePerGas).mul(storageEntryLimit).add(gasLimit);

return {
txGasPrice,
txGasLimit
};
};

export const calcSubstrateTransactionParams = (
data: {
txGasPrice: BigNumberish;
txGasLimit: BigNumberish;
} & TxConsts
): {
gasLimit: BigNumber;
storageLimit: BigNumber;
validUntil: BigNumber;
} => {
const txGasPrice = BigNumber.from(data.txGasPrice);
const txGasLimit = BigNumber.from(data.txGasLimit);
const storageByteDeposit = BigNumber.from(data.storageByteDeposit);
const txFeePerGas = BigNumber.from(data.txFeePerGas);

const storageEntryLimit = txGasPrice.and(0xffff);
const blockPeriod = txGasPrice.sub(storageEntryLimit).sub(txFeePerGas).shr(16);
const storageLimit = storageEntryLimit.mul(64);
const validUntil = blockPeriod.mul(30);
const storageEntryDeposit = storageByteDeposit.mul(64);
const gasLimit = txGasLimit.sub(storageEntryDeposit.div(txFeePerGas).mul(storageEntryLimit));

return {
gasLimit,
storageLimit,
validUntil
};
};