t-isol 0.0.2 → 0.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -10,14 +10,17 @@ interface ITransferAuthorize {
|
|
|
10
10
|
/// @param nonce unique nonce used by the authorization
|
|
11
11
|
event AuthorizeUsed(address indexed authorizer, bytes32 indexed nonce);
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
event TransferWithAuthorize(address indexed from, address indexed to, uint256 value, uint256
|
|
13
|
+
/// @notice Emitted when a transfer with authorization is executed
|
|
14
|
+
event TransferWithAuthorize(address indexed from, address indexed to, uint256 value, uint256 validAfter, uint256 validBefore, bytes32 indexed nonce);
|
|
15
15
|
|
|
16
16
|
/// @notice Emitted when a transferFrom with authorization is executed
|
|
17
|
-
event TransferFromWithAuthorize(address indexed from, address indexed to, uint256 value, uint256
|
|
17
|
+
event TransferFromWithAuthorize(address indexed from, address indexed to, uint256 value, uint256 validAfter, uint256 validBefore, bytes32 indexed nonce);
|
|
18
|
+
|
|
19
|
+
/// @notice Emitted when a approve with authorization is executed
|
|
20
|
+
event ApproveWithAuthorize(address indexed from, address indexed to, uint256 value, uint256 validAfter, uint256 validBefore, bytes32 indexed nonce);
|
|
18
21
|
|
|
19
22
|
/// @notice Emitted when a burn with authorization is executed
|
|
20
|
-
event BurnWithAuthorize(address indexed from, uint256 value, uint256
|
|
23
|
+
event BurnWithAuthorize(address indexed from, uint256 value, uint256 validAfter, uint256 validBefore, bytes32 indexed nonce);
|
|
21
24
|
|
|
22
25
|
/// @notice Returns whether a nonce has been used for a given authorizer
|
|
23
26
|
/// @param authorizer the account that signed the authorization
|
|
@@ -33,31 +36,44 @@ interface ITransferAuthorize {
|
|
|
33
36
|
address from,
|
|
34
37
|
address to,
|
|
35
38
|
uint256 value,
|
|
36
|
-
uint256
|
|
37
|
-
uint256
|
|
39
|
+
uint256 validAfter,
|
|
40
|
+
uint256 validBefore,
|
|
38
41
|
bytes32 nonce,
|
|
39
|
-
bytes calldata
|
|
42
|
+
bytes calldata signature
|
|
40
43
|
) external;
|
|
41
44
|
|
|
42
|
-
|
|
45
|
+
// ++
|
|
46
|
+
/// @notice Execute a "transfer with authorization" - typically any relayer may submit
|
|
43
47
|
function transferFromWithAuthorize(
|
|
44
48
|
address from,
|
|
45
49
|
address to,
|
|
46
50
|
uint256 value,
|
|
47
|
-
uint256
|
|
48
|
-
uint256
|
|
51
|
+
uint256 validAfter,
|
|
52
|
+
uint256 validBefore,
|
|
53
|
+
bytes32 nonce,
|
|
54
|
+
bytes calldata signature
|
|
55
|
+
) external;
|
|
56
|
+
|
|
57
|
+
// ++
|
|
58
|
+
/// @notice Execute a "approve with authorization" - typically any relayer may submit
|
|
59
|
+
function approveWithAuthorize(
|
|
60
|
+
address from,
|
|
61
|
+
address to,
|
|
62
|
+
uint256 value,
|
|
63
|
+
uint256 validAfter,
|
|
64
|
+
uint256 validBefore,
|
|
49
65
|
bytes32 nonce,
|
|
50
|
-
bytes calldata
|
|
66
|
+
bytes calldata signature
|
|
51
67
|
) external;
|
|
52
68
|
|
|
53
|
-
/// @notice Execute a "
|
|
69
|
+
/// @notice Execute a "approve with authorization" - typically any relayer may submit
|
|
54
70
|
function burnWithAuthorize(
|
|
55
71
|
address from,
|
|
56
72
|
// address to,
|
|
57
73
|
uint256 value,
|
|
58
|
-
uint256
|
|
59
|
-
uint256
|
|
74
|
+
uint256 validAfter,
|
|
75
|
+
uint256 validBefore,
|
|
60
76
|
bytes32 nonce,
|
|
61
|
-
bytes calldata
|
|
77
|
+
bytes calldata signature
|
|
62
78
|
) external;
|
|
63
79
|
}
|
|
@@ -7,22 +7,24 @@ import "./ITransferAuthorize.sol";
|
|
|
7
7
|
|
|
8
8
|
/// @title TransferAuthorize
|
|
9
9
|
/// @notice Abstract helper implementing EIP-712 verification and nonce tracking for off-chain signed authorizations
|
|
10
|
-
/// @dev Implementations should call `
|
|
10
|
+
/// @dev Implementations should call `_verify` and `_useAuthorize` before performing state changes
|
|
11
11
|
abstract contract TransferAuthorize is ITransferAuthorize, EIP712 {
|
|
12
12
|
using ECDSA for bytes32;
|
|
13
13
|
|
|
14
14
|
/// @dev mapping to track used nonces per authorizer: authorizer => nonce => used
|
|
15
15
|
mapping(address => mapping(bytes32 => bool)) private _authorizeState;
|
|
16
16
|
|
|
17
|
-
/// @dev EIP-712 type hashes for the two supported authorization structures
|
|
18
17
|
bytes32 public constant TRANSFER_TYPEHASH =
|
|
19
|
-
keccak256("TransferWithAuthorize(address from,
|
|
18
|
+
keccak256("TransferWithAuthorize(address from,address to,uint256 value,uint256 validAfter,uint256 validBefore,bytes32 nonce)");
|
|
20
19
|
|
|
21
20
|
bytes32 public constant TRANSFERFROM_TYPEHASH =
|
|
22
|
-
keccak256("TransferFromWithAuthorize(address from,
|
|
21
|
+
keccak256("TransferFromWithAuthorize(address from,address to,uint256 value,uint256 validAfter,uint256 validBefore,bytes32 nonce)");
|
|
22
|
+
|
|
23
|
+
bytes32 public constant APPROVE_TYPEHASH =
|
|
24
|
+
keccak256("ApproveWithAuthorize(address from,address to,uint256 value,uint256 validAfter,uint256 validBefore,bytes32 nonce)");
|
|
23
25
|
|
|
24
26
|
bytes32 public constant BURN_TYPEHASH =
|
|
25
|
-
keccak256("BurnWithAuthorize(address from,
|
|
27
|
+
keccak256("BurnWithAuthorize(address from,uint256 value,uint256 validAfter,uint256 validBefore,bytes32 nonce)");
|
|
26
28
|
|
|
27
29
|
/// @param name EIP-712 domain name
|
|
28
30
|
/// @param version EIP-712 domain version
|
|
@@ -50,82 +52,107 @@ abstract contract TransferAuthorize is ITransferAuthorize, EIP712 {
|
|
|
50
52
|
emit AuthorizeUsed(authorizer, nonce);
|
|
51
53
|
}
|
|
52
54
|
|
|
53
|
-
/// @dev Verify an EIP-712 typed signature
|
|
55
|
+
/// @dev Verify an EIP-712 typed signature for TransferWithAuthorize and return the recovered signer
|
|
54
56
|
function _verifyTransfer(
|
|
55
57
|
address from,
|
|
56
58
|
address to,
|
|
57
59
|
uint256 value,
|
|
58
|
-
uint256
|
|
59
|
-
uint256
|
|
60
|
+
uint256 validAfter,
|
|
61
|
+
uint256 validBefore,
|
|
60
62
|
bytes32 nonce,
|
|
61
|
-
bytes calldata
|
|
62
|
-
) internal returns (address signer) {
|
|
63
|
-
require(block.timestamp >=
|
|
64
|
-
require(block.timestamp <=
|
|
63
|
+
bytes calldata signature
|
|
64
|
+
) internal view returns (address signer) {
|
|
65
|
+
require(block.timestamp >= validAfter, "TransferAuthorize: not yet valid");
|
|
66
|
+
require(block.timestamp <= validBefore, "TransferAuthorize: expired");
|
|
65
67
|
bytes32 structHash = keccak256(
|
|
66
68
|
abi.encode(
|
|
67
69
|
TRANSFER_TYPEHASH,
|
|
68
70
|
from,
|
|
69
71
|
to,
|
|
70
72
|
value,
|
|
71
|
-
|
|
72
|
-
|
|
73
|
+
validAfter,
|
|
74
|
+
validBefore,
|
|
73
75
|
nonce
|
|
74
76
|
)
|
|
75
77
|
);
|
|
76
|
-
signer = ECDSA.recover(_hashTypedDataV4(structHash),
|
|
77
|
-
emit TransferWithAuthorize(from, to, value, timeMFG, timeEXP, nonce, auth);
|
|
78
|
+
signer = ECDSA.recover(_hashTypedDataV4(structHash), signature);
|
|
78
79
|
}
|
|
79
80
|
|
|
80
|
-
/// @dev Verify an EIP-712 typed signature
|
|
81
|
+
/// @dev Verify an EIP-712 typed signature for TransferFromWithAuthorize and return the recovered signer
|
|
81
82
|
function _verifyTransferFrom(
|
|
82
83
|
address from,
|
|
83
84
|
address to,
|
|
84
85
|
uint256 value,
|
|
85
|
-
uint256
|
|
86
|
-
uint256
|
|
86
|
+
uint256 validAfter,
|
|
87
|
+
uint256 validBefore,
|
|
87
88
|
bytes32 nonce,
|
|
88
|
-
bytes calldata
|
|
89
|
+
bytes calldata signature
|
|
89
90
|
) internal view returns (address signer) {
|
|
90
|
-
require(block.timestamp >=
|
|
91
|
-
require(block.timestamp <=
|
|
91
|
+
require(block.timestamp >= validAfter, "TransferAuthorize: not yet valid");
|
|
92
|
+
require(block.timestamp <= validBefore, "TransferAuthorize: expired");
|
|
92
93
|
bytes32 structHash = keccak256(
|
|
93
94
|
abi.encode(
|
|
94
95
|
TRANSFERFROM_TYPEHASH,
|
|
95
96
|
from,
|
|
96
97
|
to,
|
|
97
98
|
value,
|
|
98
|
-
|
|
99
|
-
|
|
99
|
+
validAfter,
|
|
100
|
+
validBefore,
|
|
101
|
+
nonce
|
|
102
|
+
)
|
|
103
|
+
);
|
|
104
|
+
signer = ECDSA.recover(_hashTypedDataV4(structHash), signature);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/// @dev Verify an EIP-712 typed signature for ApproveWithAuthorize and return the recovered signer
|
|
108
|
+
function _verifyApprove(
|
|
109
|
+
address from,
|
|
110
|
+
address to,
|
|
111
|
+
uint256 value,
|
|
112
|
+
uint256 validAfter,
|
|
113
|
+
uint256 validBefore,
|
|
114
|
+
bytes32 nonce,
|
|
115
|
+
bytes calldata signature
|
|
116
|
+
) internal view returns (address signer) {
|
|
117
|
+
require(block.timestamp >= validAfter, "TransferAuthorize: not yet valid");
|
|
118
|
+
require(block.timestamp <= validBefore, "TransferAuthorize: expired");
|
|
119
|
+
bytes32 structHash = keccak256(
|
|
120
|
+
abi.encode(
|
|
121
|
+
APPROVE_TYPEHASH,
|
|
122
|
+
from,
|
|
123
|
+
to,
|
|
124
|
+
value,
|
|
125
|
+
validAfter,
|
|
126
|
+
validBefore,
|
|
100
127
|
nonce
|
|
101
128
|
)
|
|
102
129
|
);
|
|
103
|
-
signer = ECDSA.recover(_hashTypedDataV4(structHash),
|
|
130
|
+
signer = ECDSA.recover(_hashTypedDataV4(structHash), signature);
|
|
104
131
|
}
|
|
105
132
|
|
|
106
|
-
/// @dev Verify an EIP-712 typed signature
|
|
133
|
+
/// @dev Verify an EIP-712 typed signature for BurnWithAuthorize and return the recovered signer
|
|
107
134
|
function _verifyBurn(
|
|
108
135
|
address from,
|
|
109
136
|
// address to,
|
|
110
137
|
uint256 value,
|
|
111
|
-
uint256
|
|
112
|
-
uint256
|
|
138
|
+
uint256 validAfter,
|
|
139
|
+
uint256 validBefore,
|
|
113
140
|
bytes32 nonce,
|
|
114
|
-
bytes calldata
|
|
141
|
+
bytes calldata signature
|
|
115
142
|
) internal view returns (address signer) {
|
|
116
|
-
require(block.timestamp >=
|
|
117
|
-
require(block.timestamp <=
|
|
143
|
+
require(block.timestamp >= validAfter, "TransferAuthorize: not yet valid");
|
|
144
|
+
require(block.timestamp <= validBefore, "TransferAuthorize: expired");
|
|
118
145
|
bytes32 structHash = keccak256(
|
|
119
146
|
abi.encode(
|
|
120
147
|
BURN_TYPEHASH,
|
|
121
148
|
from,
|
|
122
149
|
// to,
|
|
123
150
|
value,
|
|
124
|
-
|
|
125
|
-
|
|
151
|
+
validAfter,
|
|
152
|
+
validBefore,
|
|
126
153
|
nonce
|
|
127
154
|
)
|
|
128
155
|
);
|
|
129
|
-
signer = ECDSA.recover(_hashTypedDataV4(structHash),
|
|
156
|
+
signer = ECDSA.recover(_hashTypedDataV4(structHash), signature);
|
|
130
157
|
}
|
|
131
158
|
}
|
|
@@ -10,6 +10,7 @@ import "@openzeppelin/contracts/access/Ownable.sol";
|
|
|
10
10
|
/// @notice ERC20 extension that supports EIP-712 based `transferWithAuthorize` and `receiveWithAuthorize` flows
|
|
11
11
|
/// @dev `receiveWithAuthorize` restricts the caller to the `to` address (recipient submits the proof). `transferWithAuthorize` is open to relayers.
|
|
12
12
|
abstract contract ERC20xTransferWithAuthorize is ERC20, TransferAuthorize, ReentrancyGuard, Ownable {
|
|
13
|
+
|
|
13
14
|
constructor(
|
|
14
15
|
string memory name,
|
|
15
16
|
string memory symbol,
|
|
@@ -24,7 +25,7 @@ abstract contract ERC20xTransferWithAuthorize is ERC20, TransferAuthorize, Reent
|
|
|
24
25
|
_mint(msg.sender, initialSupply * 10 ** decimals());
|
|
25
26
|
}
|
|
26
27
|
|
|
27
|
-
/// @notice Relayer-triggered transfer using an off-chain signature
|
|
28
|
+
/// @notice Relayer-triggered transfer using an off-chain signature by `from`.
|
|
28
29
|
/// @dev This allows anyone (a relayer) to submit the signed authorization on-chain.
|
|
29
30
|
function transferWithAuthorize(
|
|
30
31
|
address from,
|
|
@@ -33,7 +34,7 @@ abstract contract ERC20xTransferWithAuthorize is ERC20, TransferAuthorize, Reent
|
|
|
33
34
|
uint256 validAfter,
|
|
34
35
|
uint256 validBefore,
|
|
35
36
|
bytes32 nonce,
|
|
36
|
-
bytes calldata
|
|
37
|
+
bytes calldata signature
|
|
37
38
|
) external override nonReentrant {
|
|
38
39
|
address signer = _verifyTransfer(
|
|
39
40
|
from,
|
|
@@ -42,14 +43,15 @@ abstract contract ERC20xTransferWithAuthorize is ERC20, TransferAuthorize, Reent
|
|
|
42
43
|
validAfter,
|
|
43
44
|
validBefore,
|
|
44
45
|
nonce,
|
|
45
|
-
|
|
46
|
+
signature
|
|
46
47
|
);
|
|
47
|
-
require(signer == from, "ERC20TransferAuthorize: invalid
|
|
48
|
+
require(signer == from, "ERC20TransferAuthorize: invalid signature");
|
|
48
49
|
_useAuthorize(from, nonce);
|
|
49
50
|
_transfer(from, to, value);
|
|
51
|
+
emit TransferWithAuthorize(from, to, value, validAfter, validBefore, nonce);
|
|
50
52
|
}
|
|
51
53
|
|
|
52
|
-
/// @notice Relayer-triggered transfer using an off-chain signature
|
|
54
|
+
/// @notice Relayer-triggered transfer using an off-chain signature by `from`.
|
|
53
55
|
/// @dev This allows anyone (a relayer) to submit the signed authorization on-chain.
|
|
54
56
|
function transferFromWithAuthorize(
|
|
55
57
|
address from,
|
|
@@ -58,7 +60,7 @@ abstract contract ERC20xTransferWithAuthorize is ERC20, TransferAuthorize, Reent
|
|
|
58
60
|
uint256 validAfter,
|
|
59
61
|
uint256 validBefore,
|
|
60
62
|
bytes32 nonce,
|
|
61
|
-
bytes calldata
|
|
63
|
+
bytes calldata signature
|
|
62
64
|
) external override nonReentrant {
|
|
63
65
|
address signer = _verifyTransferFrom(
|
|
64
66
|
from,
|
|
@@ -67,15 +69,40 @@ abstract contract ERC20xTransferWithAuthorize is ERC20, TransferAuthorize, Reent
|
|
|
67
69
|
validAfter,
|
|
68
70
|
validBefore,
|
|
69
71
|
nonce,
|
|
70
|
-
|
|
72
|
+
signature
|
|
71
73
|
);
|
|
72
|
-
require(signer == from, "ERC20TransferAuthorize: invalid
|
|
74
|
+
require(signer == from, "ERC20TransferAuthorize: invalid signature");
|
|
73
75
|
_useAuthorize(from, nonce);
|
|
74
76
|
_spendAllowance(from, to, value);
|
|
75
77
|
_transfer(from, to, value);
|
|
76
78
|
}
|
|
77
79
|
|
|
78
|
-
/// @notice Relayer-triggered transfer using an off-chain signature
|
|
80
|
+
/// @notice Relayer-triggered transfer using an off-chain signature by `from`.
|
|
81
|
+
/// @dev This allows anyone (a relayer) to submit the signed authorization on-chain.
|
|
82
|
+
function approveWithAuthorize(
|
|
83
|
+
address from,
|
|
84
|
+
address to,
|
|
85
|
+
uint256 value,
|
|
86
|
+
uint256 validAfter,
|
|
87
|
+
uint256 validBefore,
|
|
88
|
+
bytes32 nonce,
|
|
89
|
+
bytes calldata signature
|
|
90
|
+
) external override nonReentrant {
|
|
91
|
+
address signer = _verifyApprove(
|
|
92
|
+
from,
|
|
93
|
+
to,
|
|
94
|
+
value,
|
|
95
|
+
validAfter,
|
|
96
|
+
validBefore,
|
|
97
|
+
nonce,
|
|
98
|
+
signature
|
|
99
|
+
);
|
|
100
|
+
require(signer == from, "ERC20TransferAuthorize: invalid signature");
|
|
101
|
+
_useAuthorize(from, nonce);
|
|
102
|
+
_approve(from, to, value);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/// @notice Relayer-triggered transfer using an off-chain signature by `from`.
|
|
79
106
|
/// @dev This allows anyone (a relayer) to submit the signed authorization on-chain.
|
|
80
107
|
function burnWithAuthorize(
|
|
81
108
|
address from,
|
|
@@ -84,7 +111,7 @@ abstract contract ERC20xTransferWithAuthorize is ERC20, TransferAuthorize, Reent
|
|
|
84
111
|
uint256 validAfter,
|
|
85
112
|
uint256 validBefore,
|
|
86
113
|
bytes32 nonce,
|
|
87
|
-
bytes calldata
|
|
114
|
+
bytes calldata signature
|
|
88
115
|
) external override nonReentrant {
|
|
89
116
|
address signer = _verifyBurn(
|
|
90
117
|
from,
|
|
@@ -93,9 +120,9 @@ abstract contract ERC20xTransferWithAuthorize is ERC20, TransferAuthorize, Reent
|
|
|
93
120
|
validAfter,
|
|
94
121
|
validBefore,
|
|
95
122
|
nonce,
|
|
96
|
-
|
|
123
|
+
signature
|
|
97
124
|
);
|
|
98
|
-
require(signer == from, "ERC20TransferAuthorize: invalid
|
|
125
|
+
require(signer == from, "ERC20TransferAuthorize: invalid signature");
|
|
99
126
|
_useAuthorize(from, nonce);
|
|
100
127
|
_burn(from, value);
|
|
101
128
|
}
|