• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

GoodDollar / GoodProtocol / 3881987600

pending completion
3881987600

push

github

sirpy
fix: buyandbridge test

859 of 1096 branches covered (78.38%)

Branch coverage included in aggregate %.

2563 of 2779 relevant lines covered (92.23%)

93.13 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

57.14
/contracts/token/GoodDollar.sol
1
// SPDX-License-Identifier: MIT
2

3
pragma solidity >=0.8;
4
import "./ERC677.sol";
5
import "./FeesFormula.sol";
6
import "../Interfaces.sol";
7
import "./ERC20PresetMinterPauserUpgradeable.sol";
8
import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
9
import "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
10

11
/**
12
 * @title The GoodDollar V2 ERC677 token contract
13
 */
14

15
contract GoodDollar is
16
        UUPSUpgradeable,
17
        ERC677,
18
        ERC20PresetMinterPauserUpgradeable
19
{
20
        address public feeRecipient;
21

22
        IFeesFormula public formula;
23

24
        IIdentity public identity;
25

26
        uint256 public cap;
27

28
        /**
29
         * @dev constructor
30
         * @param _name The name of the token
31
         * @param _symbol The symbol of the token
32
         * @param _cap the cap of the token. no cap if 0
33
         * @param _formula the fee formula contract
34
         * @param _identity the identity contract
35
         * @param _feeRecipient the address that receives transaction fees
36
         */
37
        function initialize(
38
                string memory _name,
39
                string memory _symbol,
40
                uint256 _cap,
41
                IFeesFormula _formula,
42
                IIdentity _identity,
43
                address _feeRecipient,
44
                address _owner
45
        ) public initializer {
46
                __ERC20PresetMinterPauser_init(_name, _symbol);
30✔
47
                feeRecipient = _feeRecipient;
30✔
48
                identity = _identity;
30✔
49
                formula = _formula;
30✔
50
                cap = _cap;
30✔
51
                if (_owner != _msgSender()) {
30!
52
                        transferOwnership(_owner);
30✔
53
                        renounceRole(MINTER_ROLE, _msgSender());
28✔
54
                        renounceRole(PAUSER_ROLE, _msgSender());
28✔
55
                }
56
        }
57

58
        modifier onlyOwner() {
59
                require(hasRole(DEFAULT_ADMIN_ROLE, msg.sender), "not owner");
78!
60
                _;
78✔
61
        }
62

63
        function _authorizeUpgrade(address newImplementation)
64
                internal
65
                override
66
                onlyOwner
67
        {}
68

69
        function decimals() public view virtual override returns (uint8) {
70
                return 2;
×
71
        }
72

73
        function setFormula(IFeesFormula _formula) external onlyOwner {
74
                formula = _formula;
×
75
        }
76

77
        function setIdentity(IIdentityV2 _identity) external onlyOwner {
78
                identity = _identity;
×
79
        }
80

81
        function transferOwnership(address _owner) public onlyOwner {
82
                grantRole(DEFAULT_ADMIN_ROLE, _owner);
54✔
83
                renounceRole(DEFAULT_ADMIN_ROLE, _msgSender());
50✔
84
        }
85

86
        function owner() external view returns (address) {
87
                return getRoleMember(DEFAULT_ADMIN_ROLE, 0);
2✔
88
        }
89

90
        function isMinter(address _minter) external view returns (bool) {
91
                return hasRole(MINTER_ROLE, _minter);
4✔
92
        }
93

94
        function addMinter(address _minter) external {
95
                grantRole(MINTER_ROLE, _minter);
98✔
96
        }
97

98
        function renounceMinter() external {
99
                renounceRole(MINTER_ROLE, _msgSender());
24✔
100
        }
101

102
        function addPauser(address _pauser) external {
103
                grantRole(PAUSER_ROLE, _pauser);
24✔
104
        }
105

106
        function isPauser(address _pauser) external view returns (bool) {
107
                return hasRole(PAUSER_ROLE, _pauser);
2✔
108
        }
109

110
        /**
111
         * @dev Processes fees from given value and sends
112
         * remainder to given address
113
         * @param to the address to be sent to
114
         * @param value the value to be processed and then
115
         * transferred
116
         * @return a boolean that indicates if the operation was successful
117
         */
118
        function transfer(address to, uint256 value)
119
                public
120
                override(ERC20Upgradeable, ERC677)
121
                returns (bool)
122
        {
123
                uint256 bruttoValue = _processFees(msg.sender, to, value);
4✔
124
                return ERC20Upgradeable.transfer(to, bruttoValue);
4✔
125
        }
126

127
        /**
128
         * @dev Transfer tokens from one address to another
129
         * @param from The address which you want to send tokens from
130
         * @param to The address which you want to transfer to
131
         * @param value the amount of tokens to be transferred
132
         * @return a boolean that indicates if the operation was successful
133
         */
134
        function transferFrom(
135
                address from,
136
                address to,
137
                uint256 value
138
        ) public override returns (bool) {
139
                uint256 bruttoValue = _processFees(from, to, value);
×
140
                return super.transferFrom(from, to, bruttoValue);
×
141
        }
142

143
        /**
144
         * @dev Processes transfer fees and calls ERC677Token transferAndCall function
145
         * @param to address to transfer to
146
         * @param value the amount to transfer
147
         * @param data The data to pass to transferAndCall
148
         * @return a bool indicating if transfer function succeeded
149
         */
150
        function transferAndCall(
151
                address to,
152
                uint256 value,
153
                bytes calldata data
154
        ) external returns (bool) {
155
                uint256 bruttoValue = _processFees(msg.sender, to, value);
×
156
                return super._transferAndCall(to, bruttoValue, data);
×
157
        }
158

159
        /**
160
         * @dev Minting function
161
         * @param to the address that will receive the minted tokens
162
         * @param value the amount of tokens to mint
163
         */
164
        function mint(address to, uint256 value) public override returns (bool) {
165
                if (cap > 0) {
26!
166
                        require(
×
167
                                totalSupply() + value <= cap,
168
                                "Cannot increase supply beyond cap"
169
                        );
170
                }
171
                return super.mint(to, value);
26✔
172
        }
173

174
        /**
175
         * @dev Gets the current transaction fees
176
         * @return fee senderPays  that represents the current transaction fees and bool true if sender pays the fee or receiver
177
         */
178
        function getFees(uint256 value)
179
                public
180
                view
181
                returns (uint256 fee, bool senderPays)
182
        {
183
                return formula.getTxFees(value, address(0), address(0));
×
184
        }
185

186
        /**
187
         * @dev Gets the current transaction fees
188
         * @return fee senderPays  that represents the current transaction fees and bool true if sender pays the fee or receiver
189
         */
190
        function getFees(
191
                uint256 value,
192
                address sender,
193
                address recipient
194
        ) public view returns (uint256 fee, bool senderPays) {
195
                return formula.getTxFees(value, sender, recipient);
4✔
196
        }
197

198
        /**
199
         * @dev Sets the address that receives the transactional fees.
200
         * can only be called by owner
201
         * @param _feeRecipient The new address to receive transactional fees
202
         */
203
        function setFeeRecipient(address _feeRecipient) public onlyOwner {
204
                feeRecipient = _feeRecipient;
24✔
205
        }
206

207
        /**
208
         * @dev Sends transactional fees to feeRecipient address from given address
209
         * @param account The account that sends the fees
210
         * @param value The amount to subtract fees from
211
         * @return an uint256 that represents the given value minus the transactional fees
212
         */
213
        function _processFees(
214
                address account,
215
                address recipient,
216
                uint256 value
217
        ) internal returns (uint256) {
218
                (uint256 txFees, bool senderPays) = getFees(value, account, recipient);
4✔
219
                if (txFees > 0 && !identity.isDAOContract(msg.sender)) {
4!
220
                        require(
×
221
                                senderPays == false || value + txFees <= balanceOf(account),
222
                                "Not enough balance to pay TX fee"
223
                        );
224
                        if (account == msg.sender) {
×
225
                                super.transfer(feeRecipient, txFees);
×
226
                        } else {
227
                                super.transferFrom(account, feeRecipient, txFees);
×
228
                        }
229

230
                        return senderPays ? value : value - txFees;
×
231
                }
232
                return value;
4✔
233
        }
234
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc