Skip to content

Commit 8093074

Browse files
committed
added encodeParams to forwarder
1 parent bd5a524 commit 8093074

File tree

2 files changed

+91
-45
lines changed

2 files changed

+91
-45
lines changed

packages/ethereum-contracts/contracts/utils/Only712MacroForwarder.sol

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,23 @@ contract Only712MacroForwarder is ForwarderBase, EIP712, NonceManager {
9595

9696
// PUBLIC FUNCTIONS
9797

98+
/**
99+
* @dev Encode action and security params into the payload bytes expected by runMacro.
100+
* @param actionParams params specific to the macro action, already ABI-encoded by the caller.
101+
* @param security security related parameters
102+
* @return Encoded payload to pass to runMacro()
103+
*/
104+
function encodeParams(bytes calldata actionParams, SecurityType calldata security)
105+
external pure
106+
returns (bytes memory)
107+
{
108+
PrimaryType memory payload = PrimaryType({
109+
action: ActionType({ actionParams: actionParams }),
110+
security: security
111+
});
112+
return abi.encode(payload);
113+
}
114+
98115
/**
99116
* @dev Run the macro with encoded payload (generic + macro specific fragments).
100117
* @param m Target macro.

packages/ethereum-contracts/test/foundry/utils/Only712MacroForwarder.t.sol

Lines changed: 74 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -18,27 +18,6 @@ string constant SECURITY_TYPEDEF = "Security(string domain,string provider,uint2
1818
uint256 constant DEFAULT_NONCE = uint256(1) << 64;
1919
uint256 constant TEST_AMOUNT = 100e18;
2020

21-
// returns the encoded payload with the given nonce, timeframe and upgrade params
22-
function getPayloadWithTokenAmount(
23-
uint256 nonce,
24-
uint256 validAfter,
25-
uint256 validBefore,
26-
address token,
27-
uint256 amount
28-
) pure returns (bytes memory) {
29-
Only712MacroForwarder.PrimaryType memory payload = Only712MacroForwarder.PrimaryType({
30-
action: Only712MacroForwarder.ActionType({ actionParams: abi.encode(token, amount) }),
31-
security: Only712MacroForwarder.SecurityType({
32-
domain: SECURITY_DOMAIN,
33-
provider: SECURITY_PROVIDER,
34-
validAfter: validAfter,
35-
validBefore: validBefore,
36-
nonce: nonce
37-
})
38-
});
39-
return abi.encode(payload);
40-
}
41-
4221
// ============== Minimal macro for Only712MacroForwarder ==============
4322
// Implements IUserDefined712Macro and uses *no* postCheck logic.
4423
// Expects params (token, amount); does a SuperToken upgrade from underlying.
@@ -113,17 +92,36 @@ contract Only712MacroForwarderTest is FoundrySuperfluidTester {
11392
sf.governance.enableTrustedForwarder(sf.host, ISuperfluidToken(address(0)), address(forwarder));
11493
}
11594

116-
function getTestPayload() internal view returns (bytes memory) {
117-
return getPayloadWithTokenAmount(DEFAULT_NONCE, 0, 0, address(superToken), TEST_AMOUNT);
118-
}
119-
120-
/// @dev Fund the signer with underlying and approve super token so the signer can have tokens upgraded.
121-
function _fundSignerForUpgrade(VmSafe.Wallet memory signer, uint256 runs) internal {
122-
uint256 total = TEST_AMOUNT * runs;
123-
vm.prank(alice);
124-
token.transfer(signer.addr, total);
125-
vm.prank(signer.addr);
126-
token.approve(address(superToken), total);
95+
function testEncodeParams(
96+
uint256 nonce,
97+
uint256 validAfter,
98+
uint256 validBefore,
99+
address token,
100+
uint256 amount
101+
) external view {
102+
Only712MacroForwarder.PrimaryType memory payload = Only712MacroForwarder.PrimaryType({
103+
action: Only712MacroForwarder.ActionType({ actionParams: abi.encode(token, amount) }),
104+
security: Only712MacroForwarder.SecurityType({
105+
domain: SECURITY_DOMAIN,
106+
provider: SECURITY_PROVIDER,
107+
validAfter: validAfter,
108+
validBefore: validBefore,
109+
nonce: nonce
110+
})
111+
});
112+
bytes memory localPayload = abi.encode(payload);
113+
114+
bytes memory forwarderPayload = forwarder.encodeParams(
115+
abi.encode(token, amount),
116+
Only712MacroForwarder.SecurityType({
117+
domain: SECURITY_DOMAIN,
118+
provider: SECURITY_PROVIDER,
119+
validAfter: validAfter,
120+
validBefore: validBefore,
121+
nonce: nonce
122+
})
123+
);
124+
assertEq(localPayload, forwarderPayload, "encodeParams output must match manual PrimaryType encoding");
127125
}
128126

129127
function testRunMacro(uint256 signerPrivateKey) external {
@@ -132,15 +130,15 @@ contract Only712MacroForwarderTest is FoundrySuperfluidTester {
132130
_fundSignerForUpgrade(signer, 1);
133131

134132
uint256 signerSuperBalanceBefore = superToken.balanceOf(signer.addr);
135-
bytes memory params = getTestPayload();
133+
bytes memory params = _getTestPayload();
136134
bytes memory signatureVRS = _signPayload(signer, params);
137135
assertTrue(_runMacroAs(address(this), signer.addr, params, signatureVRS));
138136
assertEq(superToken.balanceOf(signer.addr), signerSuperBalanceBefore + TEST_AMOUNT, "signer super token balance should increase by TEST_AMOUNT");
139137
}
140138

141139
function testRevertsWhenCallerMissingProviderRole() external {
142140
VmSafe.Wallet memory signer = vm.createWallet("signer");
143-
bytes memory params = getTestPayload();
141+
bytes memory params = _getTestPayload();
144142
bytes memory signatureVRS = _signPayload(signer, params);
145143
vm.expectRevert(abi.encodeWithSelector(
146144
Only712MacroForwarder.ProviderNotAuthorized.selector, SECURITY_PROVIDER, address(0xbad)));
@@ -149,7 +147,7 @@ contract Only712MacroForwarderTest is FoundrySuperfluidTester {
149147

150148
function testDigestCalculation() external view {
151149
// check the type definition (build same way as forwarder: primary + action typedef + security typedef)
152-
string memory typeDefinition = forwarder.getTypeDefinition(minimal712Macro, getTestPayload());
150+
string memory typeDefinition = forwarder.getTypeDefinition(minimal712Macro, _getTestPayload());
153151
string memory expectedTypeDefinition = string(abi.encodePacked(
154152
PRIMARY_TYPE_NAME,
155153
"(Action action,Security security)",
@@ -159,12 +157,12 @@ contract Only712MacroForwarderTest is FoundrySuperfluidTester {
159157
assertEq(typeDefinition, expectedTypeDefinition, "typeDefinition mismatch");
160158

161159
// check the type hash
162-
bytes32 typeHash = forwarder.getTypeHash(minimal712Macro, getTestPayload());
160+
bytes32 typeHash = forwarder.getTypeHash(minimal712Macro, _getTestPayload());
163161
bytes32 expectedTypeHash = vm.eip712HashType(expectedTypeDefinition);
164162
assertEq(typeHash, expectedTypeHash, "typeHash mismatch");
165163

166164
// check the struct hash (includes type hash and the struct data)
167-
bytes memory payload = getTestPayload();
165+
bytes memory payload = _getTestPayload();
168166
bytes32 structHash = forwarder.getStructHash(minimal712Macro, payload);
169167
bytes32 actionStructHash = minimal712Macro.getActionStructHash(abi.encode(address(superToken), TEST_AMOUNT));
170168
bytes32 securityTypeHash = keccak256(abi.encodePacked(SECURITY_TYPEDEF));
@@ -185,7 +183,7 @@ contract Only712MacroForwarderTest is FoundrySuperfluidTester {
185183

186184
// check the digest
187185
bytes32 digest = forwarder.getDigest(minimal712Macro, payload);
188-
string memory dataToBeSignedJson = getDataToBeSignedJson();
186+
string memory dataToBeSignedJson = _getDataToBeSignedJson();
189187
console.log(dataToBeSignedJson);
190188
bytes32 expectedDigest = vm.eip712HashTypedData(dataToBeSignedJson);
191189
assertEq(digest, expectedDigest, "digest mismatch");
@@ -197,7 +195,7 @@ contract Only712MacroForwarderTest is FoundrySuperfluidTester {
197195

198196
for (uint256 i = 0; i < 10; i++) {
199197
uint256 nonce = forwarder.getNonce(signer.addr, key);
200-
bytes memory params = getPayloadWithTokenAmount(nonce, 0, 0, address(superToken), TEST_AMOUNT);
198+
bytes memory params = _getPayloadWithTokenAmount(nonce, 0, 0, address(superToken), TEST_AMOUNT);
201199
bytes memory signatureVRS = _signPayload(signer, params);
202200
assertTrue(_runMacroAs(address(this), signer.addr, params, signatureVRS), "runMacro with getNonce() nonce should succeed");
203201
}
@@ -208,7 +206,7 @@ contract Only712MacroForwarderTest is FoundrySuperfluidTester {
208206
_fundSignerForUpgrade(signer, 2);
209207

210208
uint256 nonce = forwarder.getNonce(signer.addr, key);
211-
bytes memory params = getPayloadWithTokenAmount(nonce, 0, 0, address(superToken), TEST_AMOUNT);
209+
bytes memory params = _getPayloadWithTokenAmount(nonce, 0, 0, address(superToken), TEST_AMOUNT);
212210
bytes memory signatureVRS = _signPayload(signer, params);
213211
assertTrue(_runMacroAs(address(this), signer.addr, params, signatureVRS));
214212

@@ -225,7 +223,7 @@ contract Only712MacroForwarderTest is FoundrySuperfluidTester {
225223
VmSafe.Wallet memory signer = vm.createWallet("signer");
226224
_fundSignerForUpgrade(signer, 2);
227225
uint256 nonce = forwarder.getNonce(signer.addr, 0);
228-
bytes memory params = getPayloadWithTokenAmount(nonce, t0, t1, address(superToken), TEST_AMOUNT);
226+
bytes memory params = _getPayloadWithTokenAmount(nonce, t0, t1, address(superToken), TEST_AMOUNT);
229227
bytes memory signatureVRS = _signPayload(signer, params);
230228

231229
// Before validAfter: revert (skip when t0 == 0 to avoid underflow)
@@ -250,7 +248,7 @@ contract Only712MacroForwarderTest is FoundrySuperfluidTester {
250248
// After validBefore: revert (use non-zero validBefore so 0 = unbounded is not used here)
251249
uint256 expiry = t0 > 0 ? t0 : 1;
252250
nonce = forwarder.getNonce(signer.addr, 0);
253-
params = getPayloadWithTokenAmount(nonce, 0, expiry, address(superToken), TEST_AMOUNT);
251+
params = _getPayloadWithTokenAmount(nonce, 0, expiry, address(superToken), TEST_AMOUNT);
254252
signatureVRS = _signPayload(signer, params);
255253
vm.warp(expiry + 1);
256254
vm.expectRevert(abi.encodeWithSelector(
@@ -265,25 +263,56 @@ contract Only712MacroForwarderTest is FoundrySuperfluidTester {
265263

266264
// Using seq=1 before seq=0 must revert
267265
uint256 nonceSeq1 = (uint256(key) << 64) | 1;
268-
bytes memory paramsSeq1 = getPayloadWithTokenAmount(nonceSeq1, 0, 0, address(superToken), TEST_AMOUNT);
266+
bytes memory paramsSeq1 = _getPayloadWithTokenAmount(nonceSeq1, 0, 0, address(superToken), TEST_AMOUNT);
269267
bytes memory sig1 = _signPayload(signer, paramsSeq1);
270268

271269
vm.expectRevert(abi.encodeWithSelector(NonceManager.InvalidNonce.selector, signer.addr, nonceSeq1));
272270
_runMacroAs(address(this), signer.addr, paramsSeq1, sig1);
273271

274272
// seq=0 must succeed
275273
uint256 nonceSeq0 = uint256(key) << 64;
276-
bytes memory paramsSeq0 = getPayloadWithTokenAmount(nonceSeq0, 0, 0, address(superToken), TEST_AMOUNT);
274+
bytes memory paramsSeq0 = _getPayloadWithTokenAmount(nonceSeq0, 0, 0, address(superToken), TEST_AMOUNT);
277275
bytes memory sig0 = _signPayload(signer, paramsSeq0);
278276
assertTrue(_runMacroAs(address(this), signer.addr, paramsSeq0, sig0));
279277

280278
// now seq=1 must succeed
281279
assertTrue(_runMacroAs(address(this), signer.addr, paramsSeq1, sig1));
282280
}
283281

282+
function _fundSignerForUpgrade(VmSafe.Wallet memory signer, uint256 runs) internal {
283+
uint256 total = TEST_AMOUNT * runs;
284+
vm.prank(alice);
285+
token.transfer(signer.addr, total);
286+
vm.prank(signer.addr);
287+
token.approve(address(superToken), total);
288+
}
289+
290+
function _getPayloadWithTokenAmount(
291+
uint256 nonce,
292+
uint256 validAfter,
293+
uint256 validBefore,
294+
address token,
295+
uint256 amount
296+
) internal view returns (bytes memory) {
297+
return forwarder.encodeParams(
298+
abi.encode(token, amount),
299+
Only712MacroForwarder.SecurityType({
300+
domain: SECURITY_DOMAIN,
301+
provider: SECURITY_PROVIDER,
302+
validAfter: validAfter,
303+
validBefore: validBefore,
304+
nonce: nonce
305+
})
306+
);
307+
}
308+
309+
function _getTestPayload() internal view returns (bytes memory) {
310+
return _getPayloadWithTokenAmount(DEFAULT_NONCE, 0, 0, address(superToken), TEST_AMOUNT);
311+
}
312+
284313
// example: https://github.com/vaquita-fi/vaquita-lisk/blob/c4964af9157c9cca9cfb167ac1a4450e36edb29e/contracts/test/VaquitaPool.t.sol#L142
285314
// The splitting up into many functions avoids stack too deep error.
286-
function getDataToBeSignedJson() internal view returns (string memory) {
315+
function _getDataToBeSignedJson() internal view returns (string memory) {
287316
return string(abi.encodePacked(
288317
'{',
289318
'"types": {', _getTypesJson(), '},',

0 commit comments

Comments
 (0)