Skip to content

Commit e7acb6b

Browse files
authored
fix: Fix GSM eip712 signature-based functions (#8)
* fix : modify GSM signature encoding * chore : lint Bindings * fix : fixes and changes for review * chore: lint * fix : verify EIP712 digests in GSM tests * fix : add modifier to test & better fail assert msg * fix : revert back to simpler tests for EIP712 digests
1 parent 859b070 commit e7acb6b

File tree

9 files changed

+293
-117
lines changed

9 files changed

+293
-117
lines changed

.gitmodules

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
11
[submodule "lib/aave-v3-origin"]
22
path = lib/aave-v3-origin
33
url = https://github.com/aave-dao/aave-v3-origin
4+
[submodule "lib/forge-std"]
5+
path = lib/forge-std
6+
url = https://github.com/foundry-rs/forge-std

foundry.toml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ test = 'tests'
55
script = 'scripts'
66
cache_path = 'cache'
77
libs = ['node_modules', 'lib']
8+
fs_permissions = [{ access = "read", path = "tests/mocks/JsonBindings.sol" }]
89
ffi = true
910
evm_version = 'paris'
1011
solc_version = '0.8.22'
@@ -19,3 +20,10 @@ ignored_warnings_from = [
1920
]
2021
optimizer = true
2122
optimizer_runs = 200
23+
24+
[bind_json]
25+
out = "tests/mocks/JsonBindings.sol"
26+
include = ["tests/helpers/EIP712Types.sol"]
27+
28+
[lint]
29+
ignore = ["tests/mocks/JsonBindings.sol"]

lib/forge-std

Submodule forge-std added at 8bbcf6e

remappings.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
forge-std/=lib/aave-v3-origin/lib/forge-std/src/
1+
forge-std/=lib/forge-std/src/
22
aave-v3-origin/=lib/aave-v3-origin/src/
33
aave-v3-origin-tests/=lib/aave-v3-origin/tests/
44
solidity-utils/=lib/aave-v3-origin/lib/solidity-utils/src/

src/contracts/facilitators/gsm/Gsm.sol

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -142,12 +142,16 @@ contract Gsm is AccessControl, VersionedInitializable, EIP712, IGsm {
142142
bytes calldata signature
143143
) external notFrozen notSeized returns (uint256, uint256) {
144144
require(deadline >= block.timestamp, 'SIGNATURE_DEADLINE_EXPIRED');
145-
bytes32 digest = keccak256(
146-
abi.encode(
147-
'\x19\x01',
148-
_domainSeparatorV4(),
149-
BUY_ASSET_WITH_SIG_TYPEHASH,
150-
abi.encode(originator, minAmount, receiver, nonces[originator]++, deadline)
145+
bytes32 digest = _hashTypedDataV4(
146+
keccak256(
147+
abi.encode(
148+
BUY_ASSET_WITH_SIG_TYPEHASH,
149+
originator,
150+
minAmount,
151+
receiver,
152+
nonces[originator]++,
153+
deadline
154+
)
151155
)
152156
);
153157
require(
@@ -175,12 +179,16 @@ contract Gsm is AccessControl, VersionedInitializable, EIP712, IGsm {
175179
bytes calldata signature
176180
) external notFrozen notSeized returns (uint256, uint256) {
177181
require(deadline >= block.timestamp, 'SIGNATURE_DEADLINE_EXPIRED');
178-
bytes32 digest = keccak256(
179-
abi.encode(
180-
'\x19\x01',
181-
_domainSeparatorV4(),
182-
SELL_ASSET_WITH_SIG_TYPEHASH,
183-
abi.encode(originator, maxAmount, receiver, nonces[originator]++, deadline)
182+
bytes32 digest = _hashTypedDataV4(
183+
keccak256(
184+
abi.encode(
185+
SELL_ASSET_WITH_SIG_TYPEHASH,
186+
originator,
187+
maxAmount,
188+
receiver,
189+
nonces[originator]++,
190+
deadline
191+
)
184192
)
185193
);
186194
require(

tests/helpers/EIP712Types.sol

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// SPDX-License-Identifier: MIT
2+
pragma solidity ^0.8.10;
3+
4+
library EIP712Types {
5+
//BuyAssetWithSig(address originator,uint256 minAmount,address receiver,uint256 nonce,uint256 deadline)
6+
struct BuyAssetWithSig {
7+
address originator;
8+
uint256 minAmount;
9+
address receiver;
10+
uint256 nonce;
11+
uint256 deadline;
12+
}
13+
14+
//SellAssetWithSig(address originator,uint256 maxAmount,address receiver,uint256 nonce,uint256 deadline)
15+
struct SellAssetWithSig {
16+
address originator;
17+
uint256 maxAmount;
18+
address receiver;
19+
uint256 nonce;
20+
uint256 deadline;
21+
}
22+
}

tests/mocks/JsonBindings.sol

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
// Automatically generated by forge bind-json.
2+
pragma solidity >=0.6.2 <0.9.0;
3+
pragma experimental ABIEncoderV2;
4+
5+
import {EIP712Types} from 'tests/helpers/EIP712Types.sol';
6+
7+
interface Vm {
8+
function parseJsonTypeArray(
9+
string calldata json,
10+
string calldata key,
11+
string calldata typeDescription
12+
) external pure returns (bytes memory);
13+
14+
function parseJsonType(
15+
string calldata json,
16+
string calldata typeDescription
17+
) external pure returns (bytes memory);
18+
19+
function parseJsonType(
20+
string calldata json,
21+
string calldata key,
22+
string calldata typeDescription
23+
) external pure returns (bytes memory);
24+
25+
function serializeJsonType(
26+
string calldata typeDescription,
27+
bytes memory value
28+
) external pure returns (string memory json);
29+
30+
function serializeJsonType(
31+
string calldata objectKey,
32+
string calldata valueKey,
33+
string calldata typeDescription,
34+
bytes memory value
35+
) external returns (string memory json);
36+
}
37+
38+
library JsonBindings {
39+
Vm constant vm = Vm(address(uint160(uint256(keccak256('hevm cheat code')))));
40+
41+
// prettier-ignore
42+
string constant schema_BuyAssetWithSig = "BuyAssetWithSig(address originator,uint256 minAmount,address receiver,uint256 nonce,uint256 deadline)";
43+
// prettier-ignore
44+
string constant schema_SellAssetWithSig = "SellAssetWithSig(address originator,uint256 maxAmount,address receiver,uint256 nonce,uint256 deadline)";
45+
46+
function serialize(
47+
EIP712Types.BuyAssetWithSig memory value
48+
) internal pure returns (string memory) {
49+
return vm.serializeJsonType(schema_BuyAssetWithSig, abi.encode(value));
50+
}
51+
52+
function serialize(
53+
EIP712Types.BuyAssetWithSig memory value,
54+
string memory objectKey,
55+
string memory valueKey
56+
) internal returns (string memory) {
57+
return vm.serializeJsonType(objectKey, valueKey, schema_BuyAssetWithSig, abi.encode(value));
58+
}
59+
60+
function deserializeBuyAssetWithSig(
61+
string memory json
62+
) public pure returns (EIP712Types.BuyAssetWithSig memory) {
63+
return
64+
abi.decode(vm.parseJsonType(json, schema_BuyAssetWithSig), (EIP712Types.BuyAssetWithSig));
65+
}
66+
67+
function deserializeBuyAssetWithSig(
68+
string memory json,
69+
string memory path
70+
) public pure returns (EIP712Types.BuyAssetWithSig memory) {
71+
return
72+
abi.decode(
73+
vm.parseJsonType(json, path, schema_BuyAssetWithSig),
74+
(EIP712Types.BuyAssetWithSig)
75+
);
76+
}
77+
78+
function deserializeBuyAssetWithSigArray(
79+
string memory json,
80+
string memory path
81+
) public pure returns (EIP712Types.BuyAssetWithSig[] memory) {
82+
return
83+
abi.decode(
84+
vm.parseJsonTypeArray(json, path, schema_BuyAssetWithSig),
85+
(EIP712Types.BuyAssetWithSig[])
86+
);
87+
}
88+
89+
function serialize(
90+
EIP712Types.SellAssetWithSig memory value
91+
) internal pure returns (string memory) {
92+
return vm.serializeJsonType(schema_SellAssetWithSig, abi.encode(value));
93+
}
94+
95+
function serialize(
96+
EIP712Types.SellAssetWithSig memory value,
97+
string memory objectKey,
98+
string memory valueKey
99+
) internal returns (string memory) {
100+
return vm.serializeJsonType(objectKey, valueKey, schema_SellAssetWithSig, abi.encode(value));
101+
}
102+
103+
function deserializeSellAssetWithSig(
104+
string memory json
105+
) public pure returns (EIP712Types.SellAssetWithSig memory) {
106+
return
107+
abi.decode(vm.parseJsonType(json, schema_SellAssetWithSig), (EIP712Types.SellAssetWithSig));
108+
}
109+
110+
function deserializeSellAssetWithSig(
111+
string memory json,
112+
string memory path
113+
) public pure returns (EIP712Types.SellAssetWithSig memory) {
114+
return
115+
abi.decode(
116+
vm.parseJsonType(json, path, schema_SellAssetWithSig),
117+
(EIP712Types.SellAssetWithSig)
118+
);
119+
}
120+
121+
function deserializeSellAssetWithSigArray(
122+
string memory json,
123+
string memory path
124+
) public pure returns (EIP712Types.SellAssetWithSig[] memory) {
125+
return
126+
abi.decode(
127+
vm.parseJsonTypeArray(json, path, schema_SellAssetWithSig),
128+
(EIP712Types.SellAssetWithSig[])
129+
);
130+
}
131+
}

tests/unit/TestGhoBase.t.sol

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,14 @@ pragma solidity ^0.8.0;
33

44
import 'forge-std/Test.sol';
55
import 'forge-std/console2.sol';
6+
import {Vm} from 'forge-std/Vm.sol';
67

78
// helpers
89
import {Constants} from '../helpers/Constants.sol';
910
import {DebtUtils} from '../helpers/DebtUtils.sol';
1011
import {Events} from '../helpers/Events.sol';
1112
import {AccessControlErrorsLib, OwnableErrorsLib} from '../helpers/ErrorsLib.sol';
13+
import {EIP712Types} from '../helpers/EIP712Types.sol';
1214

1315
// generic libs
1416
import {DataTypes} from 'aave-v3-origin/contracts/protocol/libraries/types/DataTypes.sol';
@@ -722,4 +724,30 @@ contract TestGhoBase is Test, Constants, Events {
722724
);
723725
(v, r, s) = vm.sign(ownerPk, outerHash);
724726
}
727+
728+
function _getBuyAssetTypedDataHash(
729+
EIP712Types.BuyAssetWithSig memory params
730+
) internal view returns (bytes32) {
731+
return
732+
keccak256(
733+
abi.encodePacked(
734+
'\x19\x01',
735+
GHO_GSM.DOMAIN_SEPARATOR(),
736+
vm.eip712HashStruct('BuyAssetWithSig', abi.encode(params))
737+
)
738+
);
739+
}
740+
741+
function _getSellAssetTypedDataHash(
742+
EIP712Types.SellAssetWithSig memory params
743+
) internal view returns (bytes32) {
744+
return
745+
keccak256(
746+
abi.encodePacked(
747+
'\x19\x01',
748+
GHO_GSM.DOMAIN_SEPARATOR(),
749+
vm.eip712HashStruct('SellAssetWithSig', abi.encode(params))
750+
)
751+
);
752+
}
725753
}

0 commit comments

Comments
 (0)