-
Notifications
You must be signed in to change notification settings - Fork 90
/
Copy pathForwardedMetaTransactionContext.ts
154 lines (125 loc) · 5.18 KB
/
ForwardedMetaTransactionContext.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
import { SignerWithAddress } from '@nomicfoundation/hardhat-ethers/signers';
import {
$ForwardedMetaTransactionContext,
$ForwardedMetaTransactionContext__factory,
} from '@solidstate/typechain-types';
import { expect } from 'chai';
import { ethers } from 'hardhat';
describe('ForwardedMetaTransactionContext', () => {
let instance: $ForwardedMetaTransactionContext;
let deployer: SignerWithAddress;
beforeEach(async () => {
[deployer] = await ethers.getSigners();
instance = await new $ForwardedMetaTransactionContext__factory(
deployer,
).deploy();
});
// TODO: spec
describe('__internal', () => {
describe('#_msgSender()', () => {
it('returns message sender is sender is not trusted forwarder', async () => {
const tx = await instance.$_msgSender.populateTransaction();
tx.data = ethers.concat([tx.data, ethers.randomBytes(20)]);
const result = await deployer.call(tx);
const decoded = instance.interface.decodeFunctionResult(
'$_msgSender',
result,
);
expect(decoded).to.deep.equal([await deployer.getAddress()]);
});
it('returns forwarded sender if sender is trusted forwarder', async () => {
const trustedForwarder = await ethers.getImpersonatedSigner(
await instance.getAddress(),
);
await instance.$_addTrustedForwarder(
await trustedForwarder.getAddress(),
);
const forwardedAddress = ethers.hexlify(ethers.randomBytes(20));
const tx = await instance.$_msgSender.populateTransaction();
tx.data = ethers.concat([tx.data, forwardedAddress]);
const result = await trustedForwarder.call(tx);
const decoded = instance.interface.decodeFunctionResult(
'$_msgSender',
result,
);
expect(decoded).to.deep.equal([forwardedAddress]);
});
});
describe('#_msgData()', () => {
it('returns complete message data if sender is not trusted forwarder', async () => {
const tx = await instance.$_msgData.populateTransaction();
tx.data = ethers.concat([tx.data, ethers.randomBytes(20)]);
// message data is returned as received, demonstrating the malleability of msg.data
const result = await deployer.call(tx);
const decoded = instance.interface.decodeFunctionResult(
'$_msgData',
result,
);
expect(decoded).to.deep.equal([tx.data]);
});
it('returns message data without suffix if sender is trusted forwarder', async () => {
const trustedForwarder = await ethers.getImpersonatedSigner(
await instance.getAddress(),
);
await instance.$_addTrustedForwarder(
await trustedForwarder.getAddress(),
);
const tx = await instance.$_msgData.populateTransaction();
const nonSuffixedData = tx.data;
tx.data = ethers.concat([tx.data, ethers.randomBytes(20)]);
// message data is returned as received, demonstrating the malleability of msg.data
const result = await trustedForwarder.call(tx);
const decoded = instance.interface.decodeFunctionResult(
'$_msgData',
result,
);
expect(decoded).to.deep.equal([nonSuffixedData]);
});
});
describe('#_calldataSuffixLength()', () => {
it('returns 20', async () => {
expect(await instance.$_calldataSuffixLength.staticCall()).to.equal(
20n,
);
});
});
describe('#_isTrustedForwarder(address)', () => {
it('returns trusted forwarder status of account', async () => {
expect(await instance.$_isTrustedForwarder(await deployer.getAddress()))
.to.be.false;
expect(await instance.$_isTrustedForwarder(await instance.getAddress()))
.to.be.false;
await instance.$_addTrustedForwarder(await instance.getAddress());
expect(await instance.$_isTrustedForwarder(await instance.getAddress()))
.to.be.true;
});
});
describe('#_addTrustedForwarder(address)', () => {
it('grants trusted forwarder status to account', async () => {
await instance.$_addTrustedForwarder(await instance.getAddress());
expect(await instance.$_isTrustedForwarder(await instance.getAddress()))
.to.be.true;
});
describe('reverts if', () => {
it('account is not a contract', async () => {
// this is enforced via a code check
// there's an exception for address(this), but this is difficult to test here
await expect(
instance.$_addTrustedForwarder(ethers.ZeroAddress),
).to.be.revertedWithCustomError(
instance,
'ForwardedMetaTransactionContext__TrustedForwarderMustBeContract',
);
});
});
});
describe('#_removeTrustedForwarder(address)', () => {
it('revokes trusted forwarder status from account', async () => {
await instance.$_addTrustedForwarder(await instance.getAddress());
await instance.$_removeTrustedForwarder(await instance.getAddress());
expect(await instance.$_isTrustedForwarder(await instance.getAddress()))
.to.be.false;
});
});
});
});