Skip to content

Commit 13ca7e0

Browse files
Faucet EIP1559 support (#4109)
* Faucet: EIP1559 support * Fix faucet API constant * Improve v1/v2 if statements * Increase coverage * Faucet helper changes * Fix tests * Fix tests * Fix issue after rebase * Fix linting * Remove unneeded hexpad Co-authored-by: Frederik Bolding <[email protected]>
1 parent 0a10e9a commit 13ca7e0

File tree

6 files changed

+181
-76
lines changed

6 files changed

+181
-76
lines changed

src/features/Faucet/Faucet.tsx

+9-9
Original file line numberDiff line numberDiff line change
@@ -110,9 +110,14 @@ export default function Faucet() {
110110

111111
const [network, setNetwork] = useState<Network | undefined>(undefined);
112112

113+
const txConfig =
114+
faucetState.txResult &&
115+
makeTxConfig(faucetState.txResult, networks, assets, accounts, getContactByAddressAndNetworkId);
116+
117+
const txReceipt = txConfig && makeTxReceipt(faucetState.txResult, txConfig);
118+
113119
useEffect(() => {
114-
if (faucetState.txResult) {
115-
const txReceipt = makeTxReceipt(faucetState.txResult, networks, assets);
120+
if (txReceipt) {
116121
const recipientAccount = getStoreAccount(accounts)(
117122
txReceipt.to,
118123
txReceipt.baseAsset.networkId
@@ -226,13 +231,8 @@ export default function Faucet() {
226231
<>
227232
{faucetState.txResult && (
228233
<TxReceipt
229-
txConfig={makeTxConfig(
230-
faucetState.txResult,
231-
networks,
232-
assets,
233-
getContactByAddressAndNetworkId
234-
)}
235-
txReceipt={makeTxReceipt(faucetState.txResult, networks, assets)}
234+
txConfig={txConfig}
235+
txReceipt={txReceipt}
236236
onComplete={() => reset()}
237237
resetFlow={() => reset()}
238238
queryStringsDisabled={true}

src/features/Faucet/helpers.spec.tsx

+105-10
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
import { BigNumber } from '@ethersproject/bignumber';
2+
import { hexlify } from '@ethersproject/bytes';
23

3-
import { fAccount, fAssets, fNetworks } from '@fixtures';
4+
import { fAccount, fAccounts, fAssets, fNetworks } from '@fixtures';
45
import { ITxStatus, ITxType } from '@types';
56

67
import { makeTxConfig, makeTxReceipt, possibleSolution } from './helpers';
78
import { ITxFaucetResult } from './types';
89

9-
const exampleTXResult = {
10+
const exampleTXResultV1 = {
1011
chainId: 3,
1112
data: '0x',
1213
from: '0xa500B2427458D12Ef70dd7b1E031ef99d1cc09f7',
@@ -19,6 +20,20 @@ const exampleTXResult = {
1920
value: '1'
2021
} as ITxFaucetResult;
2122

23+
const exampleTXResultV2 = {
24+
chainId: 3,
25+
data: '0x',
26+
from: '0xa500B2427458D12Ef70dd7b1E031ef99d1cc09f7',
27+
gasLimit: '21000',
28+
maxFeePerGas: '1000000000',
29+
maxPriorityFeePerGas: '1000000000',
30+
hash: '0x5049c0847681402db2c303847f2f66ac7f3a6caf63119b676374d5781b8d11e9',
31+
network: 'ropsten',
32+
nonce: 39,
33+
to: fAccount.address,
34+
value: '1'
35+
} as ITxFaucetResult;
36+
2237
describe('Faucet helpers', () => {
2338
describe('Captcha solution regex', () => {
2439
test('AbC0 should be a valid solution', () => {
@@ -31,9 +46,15 @@ describe('Faucet helpers', () => {
3146

3247
describe('makeTxConfig', () => {
3348
const getContactByAddressAndNetworkId = jest.fn();
34-
test('returns expected value', async () => {
49+
test('returns expected value for type 1 tx', async () => {
3550
expect(
36-
makeTxConfig(exampleTXResult, fNetworks, fAssets, getContactByAddressAndNetworkId)
51+
makeTxConfig(
52+
exampleTXResultV1,
53+
fNetworks,
54+
fAssets,
55+
fAccounts,
56+
getContactByAddressAndNetworkId
57+
)
3758
).toEqual({
3859
amount: '0.000000000000000001',
3960
asset: fAssets[1],
@@ -44,11 +65,43 @@ describe('Faucet helpers', () => {
4465
chainId: 3,
4566
data: '0x',
4667
from: '0xa500B2427458D12Ef70dd7b1E031ef99d1cc09f7',
47-
gasLimit: '21000',
48-
gasPrice: '1000000000',
49-
nonce: '39',
68+
gasLimit: hexlify(21000),
69+
gasPrice: hexlify(1000000000),
70+
nonce: hexlify(39),
5071
to: fAccount.address,
51-
value: '1'
72+
type: 0,
73+
value: hexlify(1)
74+
},
75+
receiverAddress: fAccount.address,
76+
senderAccount: undefined
77+
});
78+
});
79+
test('returns expected value for type 2 tx', async () => {
80+
expect(
81+
makeTxConfig(
82+
exampleTXResultV2,
83+
fNetworks,
84+
fAssets,
85+
fAccounts,
86+
getContactByAddressAndNetworkId
87+
)
88+
).toEqual({
89+
amount: '0.000000000000000001',
90+
asset: fAssets[1],
91+
baseAsset: fAssets[1],
92+
from: '0xa500B2427458D12Ef70dd7b1E031ef99d1cc09f7',
93+
networkId: 'Ropsten',
94+
rawTransaction: {
95+
chainId: 3,
96+
data: '0x',
97+
from: '0xa500B2427458D12Ef70dd7b1E031ef99d1cc09f7',
98+
gasLimit: hexlify(21000),
99+
maxFeePerGas: hexlify(1000000000),
100+
maxPriorityFeePerGas: hexlify(1000000000),
101+
type: 2,
102+
nonce: hexlify(39),
103+
to: fAccount.address,
104+
value: hexlify(1)
52105
},
53106
receiverAddress: fAccount.address,
54107
senderAccount: undefined
@@ -57,8 +110,17 @@ describe('Faucet helpers', () => {
57110
});
58111

59112
describe('makeTxReceipt', () => {
60-
test('returns expected value', async () => {
61-
expect(makeTxReceipt(exampleTXResult, fNetworks, fAssets)).toEqual({
113+
const getContactByAddressAndNetworkId = jest.fn();
114+
115+
test('returns expected value for type 1 tx', async () => {
116+
const txConfig = makeTxConfig(
117+
exampleTXResultV1,
118+
fNetworks,
119+
fAssets,
120+
fAccounts,
121+
getContactByAddressAndNetworkId
122+
);
123+
expect(makeTxReceipt(exampleTXResultV1, txConfig)).toEqual({
62124
amount: '0.000000000000000001',
63125
asset: fAssets[1],
64126
baseAsset: fAssets[1],
@@ -70,6 +132,39 @@ describe('Faucet helpers', () => {
70132
nonce: BigNumber.from(39),
71133
receiverAddress: fAccount.address,
72134
status: ITxStatus.PENDING,
135+
blockNumber: 0,
136+
timestamp: 0,
137+
metadata: undefined,
138+
to: fAccount.address,
139+
txType: ITxType.FAUCET,
140+
value: BigNumber.from('1')
141+
});
142+
});
143+
test('returns expected value for type 2 tx', async () => {
144+
const txConfig = makeTxConfig(
145+
exampleTXResultV2,
146+
fNetworks,
147+
fAssets,
148+
fAccounts,
149+
getContactByAddressAndNetworkId
150+
);
151+
expect(makeTxReceipt(exampleTXResultV2, txConfig)).toEqual({
152+
amount: '0.000000000000000001',
153+
asset: fAssets[1],
154+
baseAsset: fAssets[1],
155+
data: '0x',
156+
from: '0xa500B2427458D12Ef70dd7b1E031ef99d1cc09f7',
157+
gasLimit: BigNumber.from(21000),
158+
maxFeePerGas: BigNumber.from(1000000000),
159+
maxPriorityFeePerGas: BigNumber.from(1000000000),
160+
type: 2,
161+
hash: '0x5049c0847681402db2c303847f2f66ac7f3a6caf63119b676374d5781b8d11e9',
162+
nonce: BigNumber.from(39),
163+
receiverAddress: fAccount.address,
164+
status: ITxStatus.PENDING,
165+
blockNumber: 0,
166+
timestamp: 0,
167+
metadata: undefined,
73168
to: fAccount.address,
74169
txType: ITxType.FAUCET,
75170
value: BigNumber.from('1')

src/features/Faucet/helpers.tsx

+23-54
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,13 @@
11
import { BigNumber } from '@ethersproject/bignumber';
2-
import { formatEther } from '@ethersproject/units';
32

4-
import { getBaseAssetByNetwork } from '@services/Store';
3+
import { makeTxConfigFromTx, toTxReceipt } from '@helpers';
54
import {
6-
Asset,
75
ExtendedAsset,
86
ExtendedContact,
97
ITxConfig,
10-
ITxNonce,
118
ITxReceipt,
129
ITxStatus,
1310
ITxType,
14-
ITxValue,
1511
Network,
1612
NetworkId,
1713
StoreAccount,
@@ -33,71 +29,44 @@ export const makeTxConfig = (
3329
txResult: ITxFaucetResult,
3430
networks: Network[],
3531
assets: ExtendedAsset[],
32+
accounts: StoreAccount[],
3633
getContactByAddressAndNetworkId: (
3734
address: TAddress,
3835
networkId: NetworkId
3936
) => ExtendedContact | undefined
4037
): ITxConfig => {
4138
const network = getNetworkByLowercaseId(txResult.network, networks);
42-
const baseAsset: Asset = getBaseAssetByNetwork({
43-
network,
44-
assets
45-
})!;
4639

4740
// Guaranteed to work as Faucet address is in STATIC_CONTACTS
4841
const senderContact = getContactByAddressAndNetworkId(txResult.from, network.id)!;
4942

43+
const newTxResult = {
44+
...txResult,
45+
gasLimit: BigNumber.from(txResult.gasLimit),
46+
gasPrice: 'gasPrice' in txResult ? BigNumber.from(txResult.gasPrice) : undefined,
47+
maxPriorityFeePerGas:
48+
'maxPriorityFeePerGas' in txResult
49+
? BigNumber.from(txResult.maxPriorityFeePerGas)
50+
: undefined,
51+
maxFeePerGas: 'maxFeePerGas' in txResult ? BigNumber.from(txResult.maxFeePerGas) : undefined,
52+
type: 'maxPriorityFeePerGas' in txResult && 'maxFeePerGas' in txResult ? 2 : 0,
53+
value: BigNumber.from(txResult.value)
54+
};
55+
5056
/*
5157
* ITxConfig.senderAccount uses type StoreAccount, but in this case the user is the recipient and the faucet is the sender.
5258
* getContactByAddressAndNetworkId() returns ExtendedContact, which is the closest we can get.
5359
* The result is casted to make it compatible with ITxConfig.
5460
*/
55-
return {
56-
rawTransaction: {
57-
to: txResult.to,
58-
value: txResult.value as ITxValue,
59-
gasLimit: txResult.gasLimit,
60-
data: txResult.data,
61-
gasPrice: txResult.gasPrice,
62-
nonce: txResult.nonce.toString() as ITxNonce,
63-
chainId: txResult.chainId,
64-
from: txResult.from
65-
},
66-
amount: formatEther(txResult.value),
67-
receiverAddress: txResult.to,
68-
senderAccount: (senderContact as unknown) as StoreAccount,
69-
from: txResult.from,
70-
asset: baseAsset,
71-
baseAsset,
72-
networkId: network.id
61+
const txConfig = {
62+
...makeTxConfigFromTx(newTxResult, assets, network, accounts),
63+
senderAccount: (senderContact as unknown) as StoreAccount
7364
};
74-
};
7565

76-
export const makeTxReceipt = (
77-
txResult: ITxFaucetResult,
78-
networks: Network[],
79-
assets: ExtendedAsset[]
80-
): ITxReceipt => {
81-
const network = getNetworkByLowercaseId(txResult.network, networks);
82-
const baseAsset: Asset = getBaseAssetByNetwork({
83-
network,
84-
assets
85-
})!;
66+
return txConfig;
67+
};
8668

87-
return {
88-
asset: baseAsset,
89-
baseAsset,
90-
txType: ITxType.FAUCET,
91-
status: ITxStatus.PENDING,
92-
receiverAddress: txResult.to,
93-
amount: formatEther(txResult.value),
94-
data: txResult.data,
95-
gasPrice: BigNumber.from(txResult.gasPrice),
96-
gasLimit: BigNumber.from(txResult.gasLimit),
97-
to: txResult.to,
98-
from: txResult.from,
99-
value: BigNumber.from(txResult.value),
100-
nonce: BigNumber.from(txResult.nonce),
101-
hash: txResult.hash
102-
};
69+
export const makeTxReceipt = (txResult: ITxFaucetResult, txConfig: ITxConfig): ITxReceipt => {
70+
const txReceipt = toTxReceipt(txResult.hash, ITxStatus.PENDING)(ITxType.FAUCET, txConfig);
71+
return txReceipt;
10372
};

src/features/Faucet/types.ts

+17-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { ITxData, ITxGasLimit, ITxGasPrice, ITxHash, TAddress } from '@types';
22

3-
export interface ITxFaucetResult {
3+
interface ITxFaucetResultV1 {
44
chainId: number;
55
data: ITxData;
66
from: TAddress;
@@ -13,6 +13,22 @@ export interface ITxFaucetResult {
1313
value: string;
1414
}
1515

16+
interface ITxFaucetResultV2 {
17+
chainId: number;
18+
data: ITxData;
19+
from: TAddress;
20+
gasLimit: ITxGasLimit;
21+
maxFeePerGas: ITxGasPrice;
22+
maxPriorityFeePerGas: ITxGasPrice;
23+
hash: ITxHash;
24+
network: string;
25+
nonce: number;
26+
to: TAddress;
27+
value: string;
28+
}
29+
30+
export type ITxFaucetResult = ITxFaucetResultV1 | ITxFaucetResultV2;
31+
1632
export interface FaucetState {
1733
step: number;
1834
challenge?: {

src/helpers/transaction.ts

+5-1
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,10 @@ type TxBeforeGasLimit = DistributiveOmit<ITxObject, 'nonce' | 'gasLimit'> & {
8686
gasLimit?: ITxGasLimit;
8787
};
8888
type TxBeforeNonce = DistributiveOmit<ITxObject, 'nonce'> & { nonce?: ITxNonce };
89+
type TxResponseBeforeBroadcast = DistributiveOmit<TransactionResponse, 'confirmations' | 'wait'> & {
90+
confirmations?: number;
91+
wait?(confirmations?: number): Promise<TransactionReceipt>;
92+
};
8993

9094
const formatGas = (tx: ITxObject) =>
9195
isType2Tx(tx)
@@ -251,7 +255,7 @@ export const makeTxConfigFromSignedTx = (
251255

252256
// needs testing
253257
export const makeTxConfigFromTx = (
254-
decodedTx: TransactionResponse | ITxObject,
258+
decodedTx: TxResponseBeforeBroadcast | ITxObject,
255259
assets: ExtendedAsset[],
256260
network: Network,
257261
accounts: StoreAccount[]

src/services/ApiService/Faucet/types.ts

+22-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ export interface FaucetChallengeResponse {
1515
};
1616
}
1717

18-
export interface FaucetSolvedChallengeResponse {
18+
interface FaucetSolvedChallengeResponseV1 {
1919
success: true;
2020
result: {
2121
chainId: number;
@@ -30,3 +30,24 @@ export interface FaucetSolvedChallengeResponse {
3030
value: string;
3131
};
3232
}
33+
34+
interface FaucetSolvedChallengeResponseV2 {
35+
success: true;
36+
result: {
37+
chainId: number;
38+
data: string;
39+
from: string;
40+
gasLimit: string;
41+
maxFeePerGas: string;
42+
maxPriorityFeePerGas: string;
43+
hash: string;
44+
network: string;
45+
nonce: number;
46+
to: string;
47+
value: string;
48+
};
49+
}
50+
51+
export type FaucetSolvedChallengeResponse =
52+
| FaucetSolvedChallengeResponseV1
53+
| FaucetSolvedChallengeResponseV2;

0 commit comments

Comments
 (0)