@@ -6,164 +6,65 @@ import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
66import "@1inch/solidity-utils/contracts/libraries/AddressSet.sol " ;
77
88import "./interfaces/IERC20Pods.sol " ;
9- import "./interfaces/IPod .sol " ;
9+ import "./TokenPodsLib .sol " ;
1010import "./libs/ReentrancyGuard.sol " ;
1111
1212abstract contract ERC20Pods is ERC20 , IERC20Pods , ReentrancyGuardExt {
13- using AddressSet for AddressSet.Data;
14- using AddressArray for AddressArray.Data;
13+ using TokenPodsLib for TokenPodsLib.Data;
1514 using ReentrancyGuardLib for ReentrancyGuardLib.Data;
1615
17- error PodAlreadyAdded ();
18- error PodNotFound ();
19- error InvalidPodAddress ();
2016 error PodsLimitReachedForAccount ();
21- error InsufficientGas ();
22-
23- uint256 private constant _POD_CALL_GAS_LIMIT = 200_000 ;
2417
2518 uint256 public immutable podsLimit;
2619
2720 ReentrancyGuardLib.Data private _guard;
28- mapping ( address => AddressSet .Data) private _pods;
21+ TokenPodsLib .Data private _pods;
2922
3023 constructor (uint256 podsLimit_ ) {
3124 podsLimit = podsLimit_;
3225 _guard.init ();
3326 }
3427
3528 function hasPod (address account , address pod ) public view virtual returns (bool ) {
36- return _pods[account]. contains ( pod);
29+ return _pods. hasPod (account, pod);
3730 }
3831
3932 function podsCount (address account ) public view virtual returns (uint256 ) {
40- return _pods[account]. length ( );
33+ return _pods. podsCount (account );
4134 }
4235
4336 function podAt (address account , uint256 index ) public view virtual returns (address ) {
44- return _pods[account]. at ( index);
37+ return _pods. podAt (account, index);
4538 }
4639
4740 function pods (address account ) public view virtual returns (address [] memory ) {
48- return _pods[account].items. get ( );
41+ return _pods. pods (account );
4942 }
5043
51- function balanceOf (address account ) public nonReentrantView (_guard) view override (IERC20 , ERC20 ) returns (uint256 ) {
44+ function balanceOf (address account ) public nonReentrantView (_guard) view override (IERC20 , ERC20 ) virtual returns (uint256 ) {
5245 return super .balanceOf (account);
5346 }
5447
55- function podBalanceOf (address pod , address account ) public nonReentrantView (_guard) view returns (uint256 ) {
56- if (hasPod (account, pod)) {
57- return balanceOf (account);
58- }
59- return 0 ;
48+ function podBalanceOf (address pod , address account ) public nonReentrantView (_guard) view virtual returns (uint256 ) {
49+ return _pods.podBalanceOf (account, pod, balanceOf (account));
6050 }
6151
6252 function addPod (address pod ) public virtual {
63- _addPod ( msg .sender , pod);
53+ if (_pods. addPod ( msg .sender , pod, balanceOf ( msg . sender )) > podsLimit) revert PodsLimitReachedForAccount ( );
6454 }
6555
6656 function removePod (address pod ) public virtual {
67- _removePod (msg .sender , pod);
57+ _pods. removePod (msg .sender , pod, balanceOf ( msg . sender ) );
6858 }
6959
7060 function removeAllPods () public virtual {
71- _removeAllPods (msg .sender );
72- }
73-
74- function _addPod (address account , address pod ) internal virtual {
75- if (pod == address (0 )) revert InvalidPodAddress ();
76- if (! _pods[account].add (pod)) revert PodAlreadyAdded ();
77- if (_pods[account].length () > podsLimit) revert PodsLimitReachedForAccount ();
78-
79- uint256 balance = balanceOf (account);
80- if (balance > 0 ) {
81- _updateBalances (pod, address (0 ), account, balance);
82- }
83- }
84-
85- function _removePod (address account , address pod ) internal virtual {
86- if (! _pods[account].remove (pod)) revert PodNotFound ();
87-
88- uint256 balance = balanceOf (account);
89- if (balance > 0 ) {
90- _updateBalances (pod, account, address (0 ), balance);
91- }
92- }
93-
94- function _removeAllPods (address account ) internal virtual {
95- address [] memory items = _pods[account].items.get ();
96- uint256 balance = balanceOf (account);
97- unchecked {
98- for (uint256 i = items.length ; i > 0 ; i-- ) {
99- if (balance > 0 ) {
100- _updateBalances (items[i - 1 ], account, address (0 ), balance);
101- }
102- _pods[account].remove (items[i - 1 ]);
103- }
104- }
105- }
106-
107- /// @notice Assembly implementation of the gas limited call to avoid return gas bomb,
108- // moreover call to a destructed pod would also revert even inside try-catch block in Solidity 0.8.17
109- /// @dev try IPod(pod).updateBalances{gas: _POD_CALL_GAS_LIMIT}(from, to, amount) {} catch {}
110- function _updateBalances (address pod , address from , address to , uint256 amount ) private {
111- bytes4 selector = IPod.updateBalances.selector ;
112- bytes4 exception = InsufficientGas.selector ;
113- assembly { // solhint-disable-line no-inline-assembly
114- let ptr := mload (0x40 )
115- mstore (ptr, selector)
116- mstore (add (ptr, 0x04 ), from)
117- mstore (add (ptr, 0x24 ), to)
118- mstore (add (ptr, 0x44 ), amount)
119-
120- if lt (div (mul (gas (), 63 ), 64 ), _POD_CALL_GAS_LIMIT) {
121- mstore (0 , exception)
122- revert (0 , 4 )
123- }
124- pop (call (_POD_CALL_GAS_LIMIT, pod, 0 , ptr, 0x64 , 0 , 0 ))
125- }
61+ _pods.removeAllPods (msg .sender , balanceOf (msg .sender ));
12662 }
12763
12864 // ERC20 Overrides
12965
13066 function _afterTokenTransfer (address from , address to , uint256 amount ) internal nonReentrant (_guard) override virtual {
13167 super ._afterTokenTransfer (from, to, amount);
132-
133- unchecked {
134- if (amount > 0 && from != to) {
135- address [] memory a = _pods[from].items.get ();
136- address [] memory b = _pods[to].items.get ();
137- uint256 aLength = a.length ;
138- uint256 bLength = b.length ;
139-
140- for (uint256 i = 0 ; i < aLength; i++ ) {
141- address pod = a[i];
142-
143- uint256 j;
144- for (j = 0 ; j < bLength; j++ ) {
145- if (pod == b[j]) {
146- // Both parties are participating of the same Pod
147- _updateBalances (pod, from, to, amount);
148- b[j] = address (0 );
149- break ;
150- }
151- }
152-
153- if (j == bLength) {
154- // Sender is participating in a Pod, but receiver is not
155- _updateBalances (pod, from, address (0 ), amount);
156- }
157- }
158-
159- for (uint256 j = 0 ; j < bLength; j++ ) {
160- address pod = b[j];
161- if (pod != address (0 )) {
162- // Receiver is participating in a Pod, but sender is not
163- _updateBalances (pod, address (0 ), to, amount);
164- }
165- }
166- }
167- }
68+ _pods.updateBalances (from, to, amount);
16869 }
16970}
0 commit comments