@@ -76,6 +76,20 @@ contract XCAmple is IERC20Upgradeable, OwnableUpgradeable {
76
76
// because the gons xcAmple conversion might change before it's fully paid.
77
77
mapping (address => mapping (address => uint256 )) private _allowedXCAmples;
78
78
79
+ // EIP-2612: permit – 712-signed approvals
80
+ // https://eips.ethereum.org/EIPS/eip-2612
81
+ bytes public constant EIP712_REVISION = "1 " ;
82
+ bytes32 public constant EIP712_DOMAIN = keccak256 (
83
+ "EIP712Domain(string name,string version,uint256 chainId,address verifyingContract) "
84
+ );
85
+ bytes32 public constant PERMIT_TYPEHASH = keccak256 (
86
+ "Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline) "
87
+ );
88
+ bytes32 public DOMAIN_SEPARATOR;
89
+
90
+ // EIP-2612: keeps track of number of permits per address
91
+ mapping (address => uint256 ) private _nonces;
92
+
79
93
/**
80
94
* @param controller_ The address of the controller contract to use for authentication.
81
95
*/
@@ -130,6 +144,20 @@ contract XCAmple is IERC20Upgradeable, OwnableUpgradeable {
130
144
_totalSupply = 0 ;
131
145
132
146
_gonsPerAMPL = TOTAL_GONS.div (globalAMPLSupply);
147
+
148
+ uint256 chainId;
149
+ assembly {
150
+ chainId := chainid ()
151
+ }
152
+ DOMAIN_SEPARATOR = keccak256 (
153
+ abi.encode (
154
+ EIP712_DOMAIN,
155
+ keccak256 (bytes (name)),
156
+ keccak256 (EIP712_REVISION),
157
+ chainId,
158
+ address (this )
159
+ )
160
+ );
133
161
}
134
162
135
163
/**
@@ -175,6 +203,28 @@ contract XCAmple is IERC20Upgradeable, OwnableUpgradeable {
175
203
return _gonBalances[who].div (_gonsPerAMPL);
176
204
}
177
205
206
+ /**
207
+ * @param who The address to query.
208
+ * @return The gon balance of the specified address.
209
+ */
210
+ function scaledBalanceOf (address who ) external view returns (uint256 ) {
211
+ return _gonBalances[who];
212
+ }
213
+
214
+ /**
215
+ * @return the total number of gons.
216
+ */
217
+ function scaledTotalSupply () external pure returns (uint256 ) {
218
+ return TOTAL_GONS;
219
+ }
220
+
221
+ /**
222
+ * @return The number of successful permits by the specified address.
223
+ */
224
+ function nonces (address who ) public view returns (uint256 ) {
225
+ return _nonces[who];
226
+ }
227
+
178
228
/**
179
229
* @dev Transfer tokens to a specified address.
180
230
* @param to The address to transfer to.
@@ -188,8 +238,26 @@ contract XCAmple is IERC20Upgradeable, OwnableUpgradeable {
188
238
returns (bool )
189
239
{
190
240
uint256 gonValue = value.mul (_gonsPerAMPL);
241
+
191
242
_gonBalances[msg .sender ] = _gonBalances[msg .sender ].sub (gonValue);
192
243
_gonBalances[to] = _gonBalances[to].add (gonValue);
244
+
245
+ emit Transfer (msg .sender , to, value);
246
+ return true ;
247
+ }
248
+
249
+ /**
250
+ * @dev Transfer all of the sender's wallet balance to a specified address.
251
+ * @param to The address to transfer to.
252
+ * @return True on success, false otherwise.
253
+ */
254
+ function transferAll (address to ) external validRecipient (to) returns (bool ) {
255
+ uint256 gonValue = _gonBalances[msg .sender ];
256
+ uint256 value = gonValue.div (_gonsPerAMPL);
257
+
258
+ delete _gonBalances[msg .sender ];
259
+ _gonBalances[to] = _gonBalances[to].add (gonValue);
260
+
193
261
emit Transfer (msg .sender , to, value);
194
262
return true ;
195
263
}
@@ -218,10 +286,29 @@ contract XCAmple is IERC20Upgradeable, OwnableUpgradeable {
218
286
_allowedXCAmples[from][msg .sender ] = _allowedXCAmples[from][msg .sender ].sub (value);
219
287
220
288
uint256 gonValue = value.mul (_gonsPerAMPL);
289
+
221
290
_gonBalances[from] = _gonBalances[from].sub (gonValue);
222
291
_gonBalances[to] = _gonBalances[to].add (gonValue);
292
+
223
293
emit Transfer (from, to, value);
294
+ return true ;
295
+ }
296
+
297
+ /**
298
+ * @dev Transfer all balance tokens from one address to another.
299
+ * @param from The address you want to send tokens from.
300
+ * @param to The address you want to transfer to.
301
+ */
302
+ function transferAllFrom (address from , address to ) external validRecipient (to) returns (bool ) {
303
+ uint256 gonValue = _gonBalances[from];
304
+ uint256 value = gonValue.div (_gonsPerAMPL);
305
+
306
+ _allowedXCAmples[from][msg .sender ] = _allowedXCAmples[from][msg .sender ].sub (value);
307
+
308
+ delete _gonBalances[from];
309
+ _gonBalances[to] = _gonBalances[to].add (gonValue);
224
310
311
+ emit Transfer (from, to, value);
225
312
return true ;
226
313
}
227
314
@@ -238,6 +325,7 @@ contract XCAmple is IERC20Upgradeable, OwnableUpgradeable {
238
325
*/
239
326
function approve (address spender , uint256 value ) external override returns (bool ) {
240
327
_allowedXCAmples[msg .sender ][spender] = value;
328
+
241
329
emit Approval (msg .sender , spender, value);
242
330
return true ;
243
331
}
@@ -253,6 +341,7 @@ contract XCAmple is IERC20Upgradeable, OwnableUpgradeable {
253
341
_allowedXCAmples[msg .sender ][spender] = _allowedXCAmples[msg .sender ][spender].add (
254
342
addedValue
255
343
);
344
+
256
345
emit Approval (msg .sender , spender, _allowedXCAmples[msg .sender ][spender]);
257
346
return true ;
258
347
}
@@ -270,6 +359,7 @@ contract XCAmple is IERC20Upgradeable, OwnableUpgradeable {
270
359
} else {
271
360
_allowedXCAmples[msg .sender ][spender] = oldValue.sub (subtractedValue);
272
361
}
362
+
273
363
emit Approval (msg .sender , spender, _allowedXCAmples[msg .sender ][spender]);
274
364
return true ;
275
365
}
@@ -306,4 +396,41 @@ contract XCAmple is IERC20Upgradeable, OwnableUpgradeable {
306
396
307
397
emit Transfer (who, address (0 ), xcAmpleAmount);
308
398
}
399
+
400
+ /**
401
+ * @dev Allows for approvals to be made via secp256k1 signatures.
402
+ * @param owner The owner of the funds
403
+ * @param spender The spender
404
+ * @param value The amount
405
+ * @param deadline The deadline timestamp, type(uint256).max for max deadline
406
+ * @param v Signature param
407
+ * @param s Signature param
408
+ * @param r Signature param
409
+ */
410
+ function permit (
411
+ address owner ,
412
+ address spender ,
413
+ uint256 value ,
414
+ uint256 deadline ,
415
+ uint8 v ,
416
+ bytes32 r ,
417
+ bytes32 s
418
+ ) public {
419
+ require (block .timestamp <= deadline);
420
+
421
+ uint256 ownerNonce = _nonces[owner];
422
+ bytes32 permitDataDigest = keccak256 (
423
+ abi.encode (PERMIT_TYPEHASH, owner, spender, value, ownerNonce, deadline)
424
+ );
425
+ bytes32 digest = keccak256 (
426
+ abi.encodePacked ("\x19\x01 " , DOMAIN_SEPARATOR, permitDataDigest)
427
+ );
428
+
429
+ require (owner == ecrecover (digest, v, r, s));
430
+
431
+ _nonces[owner] = ownerNonce.add (1 );
432
+
433
+ _allowedXCAmples[owner][spender] = value;
434
+ emit Approval (owner, spender, value);
435
+ }
309
436
}
0 commit comments