Skip to content

Commit 502ca82

Browse files
committed
chore: remove old addresses
1 parent 52889b4 commit 502ca82

File tree

4 files changed

+706
-0
lines changed

4 files changed

+706
-0
lines changed
Lines changed: 267 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,267 @@
1+
// SPDX-License-Identifier: MIT
2+
// NatSpec format convention - https://docs.soliditylang.org/en/v0.5.10/natspec-format.html
3+
pragma solidity 0.8.26;
4+
5+
import { EnumerableSet } from "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";
6+
import { Initializable } from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
7+
import { UUPSUpgradeable } from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol";
8+
import { AccessControlledUpgradeable } from "contracts/core/primitives/upgradeable/AccessControlledUpgradeable.sol";
9+
// solhint-disable-next-line max-line-length
10+
import { ReentrancyGuardTransientUpgradeable } from "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardTransientUpgradeable.sol";
11+
import { FeesCollectorUpgradeable } from "contracts/core/primitives/upgradeable/FeesCollectorUpgradeable.sol";
12+
13+
import { IRightsAccessAgreement } from "contracts/core/interfaces/rights/IRightsAccessAgreement.sol";
14+
import { ITollgate } from "contracts/core/interfaces/economics/ITollgate.sol";
15+
import { ITreasury } from "contracts/core/interfaces/economics/ITreasury.sol";
16+
import { TreasuryOps } from "contracts/core/libraries/TreasuryOps.sol";
17+
import { FeesOps } from "contracts/core/libraries/FeesOps.sol";
18+
import { T } from "contracts/core/primitives/Types.sol";
19+
20+
contract RightsAccessAgreement is
21+
Initializable,
22+
UUPSUpgradeable,
23+
AccessControlledUpgradeable,
24+
ReentrancyGuardTransientUpgradeable,
25+
FeesCollectorUpgradeable,
26+
IRightsAccessAgreement
27+
{
28+
using FeesOps for uint256;
29+
using TreasuryOps for address;
30+
using EnumerableSet for EnumerableSet.UintSet;
31+
32+
/// KIM: any initialization here is ephimeral and not included in bytecode..
33+
/// so the code within a logic contract’s constructor or global declaration
34+
/// will never be executed in the context of the proxy’s state
35+
/// https://docs.openzeppelin.com/upgrades-plugins/1.x/proxies#the-constructor-caveat
36+
37+
/// @custom:oz-upgrades-unsafe-allow state-variable-immutable
38+
ITreasury public immutable TREASURY;
39+
/// @custom:oz-upgrades-unsafe-allow state-variable-immutable
40+
ITollgate public immutable TOLLGATE;
41+
42+
/// @dev Holds a bounded key expressing the agreement between the parts.
43+
mapping(uint256 => T.Agreement) private _agreements;
44+
/// @dev Holds a the list of actives proof for accounts.
45+
mapping(address => EnumerableSet.UintSet) private _actives;
46+
47+
/// @notice Emitted when an agreement is created.
48+
/// @param initiator The account that initiated or created the agreement.
49+
/// @param proof The unique identifier (hash or proof) of the created agreement.
50+
event AgreementCreated(address indexed initiator, uint256 proof);
51+
52+
/// @notice Emitted when an agreement is settled by the designated broker or authorized account.
53+
/// @param broker The account that facilitated the agreement settlement.
54+
/// @param proof The unique identifier (hash or proof) of the settled agreement.
55+
event AgreementSettled(address indexed broker, address indexed counterparty, uint256 proof);
56+
57+
/// @notice Emitted when an agreement is canceled by the broker or another authorized account.
58+
/// @param initiator The account that initiated the cancellation.
59+
/// @param proof The unique identifier (hash or proof) of the canceled agreement.
60+
event AgreementCancelled(address indexed initiator, uint256 proof);
61+
62+
/// @dev Custom error thrown when the provided proof for an agreement is invalid.
63+
error InvalidAgreementProof();
64+
65+
/// @dev Custom error thrown for invalid operations on an agreement, with a descriptive message.
66+
/// @param message A string explaining the invalid operation.
67+
error InvalidAgreementOp(string message);
68+
69+
/// @notice Ensures the agreement associated with the provided `proof` is valid and active.
70+
modifier onlyValidAgreement(uint256 proof) {
71+
T.Agreement memory agreement = getAgreement(proof);
72+
if (!agreement.active || agreement.initiator == address(0)) {
73+
revert InvalidAgreementOp("Invalid inactive agreement.");
74+
}
75+
_;
76+
}
77+
78+
/// @custom:oz-upgrades-unsafe-allow constructor
79+
constructor(address treasury, address tollgate) {
80+
/// https://forum.openzeppelin.com/t/uupsupgradeable-vulnerability-post-mortem/15680
81+
/// https://forum.openzeppelin.com/t/what-does-disableinitializers-function-mean/28730/5
82+
_disableInitializers();
83+
// we need to collect the fees during the agreement creation.
84+
TOLLGATE = ITollgate(tollgate);
85+
TREASURY = ITreasury(treasury);
86+
}
87+
88+
/// Initialize the proxy state.
89+
function initialize(address accessManager) public initializer {
90+
__UUPSUpgradeable_init();
91+
__AccessControlled_init(accessManager);
92+
__FeesCollector_init(address(TREASURY));
93+
__ReentrancyGuardTransient_init();
94+
}
95+
96+
/// @notice Creates and stores a new agreement.
97+
/// @param amount The total amount committed.
98+
/// @param currency The currency used for the agreement.
99+
/// @param broker The authorized account to manage the agreement.
100+
/// @param parties The parties in the agreement.
101+
/// @param payload Additional data for execution.
102+
function createAgreement(
103+
uint256 amount,
104+
address currency,
105+
address broker,
106+
address[] calldata parties,
107+
bytes calldata payload
108+
) external returns (uint256) {
109+
// IMPORTANT: The process of distributing funds to accounts should be handled within the policy logic.
110+
uint256 confirmed = msg.sender.safeDeposit(amount, currency);
111+
T.Agreement memory agreement = previewAgreement(confirmed, currency, broker, parties, payload);
112+
// only the initiator can operate with this agreement proof, or transfer the proof to the other party..
113+
// each agreement is unique and immutable, ensuring that it cannot be modified or reconstructed.
114+
uint256 proof = _createProof(agreement);
115+
_storeAgreement(proof, agreement);
116+
117+
emit AgreementCreated(msg.sender, proof);
118+
return proof;
119+
}
120+
121+
/// @notice Allows the initiator to quit the agreement and receive the committed funds.
122+
/// @param proof The unique identifier of the agreement.
123+
function quitAgreement(uint256 proof) external onlyValidAgreement(proof) nonReentrant returns (T.Agreement memory) {
124+
T.Agreement memory agreement = getAgreement(proof);
125+
if (agreement.initiator != msg.sender) {
126+
revert InvalidAgreementOp("Only initiator can close the agreement.");
127+
}
128+
129+
// a partial rollback amount is registered in treasury..
130+
uint256 available = agreement.available; // initiator rollback
131+
address initiator = agreement.initiator; // the original initiator
132+
uint256 fees = agreement.fees; // keep fees as penalty
133+
address currency = agreement.currency;
134+
135+
_closeAgreement(proof); // close the agreement
136+
_sumLedgerEntry(address(this), fees, currency);
137+
_registerFundsInTreasury(initiator, available, currency);
138+
139+
emit AgreementCancelled(initiator, proof);
140+
return agreement;
141+
}
142+
143+
/// @notice Retrieves the list of active proofs associated with a specific account.
144+
/// @param account The address of the account whose active proofs are being queried.
145+
function getActiveProofs(address account) public view returns (uint256[] memory) {
146+
return _actives[account].values();
147+
}
148+
149+
/// @notice Retrieves the details of an agreement based on the provided proof.
150+
/// @param proof The unique identifier (hash) of the agreement.
151+
function getAgreement(uint256 proof) public view returns (T.Agreement memory) {
152+
return _agreements[proof];
153+
}
154+
155+
/// @notice Settles an agreement by marking it inactive and transferring funds to the counterparty.
156+
/// @param proof The unique identifier of the agreement.
157+
/// @param counterparty The address that will receive the funds upon settlement.
158+
function settleAgreement(
159+
uint256 proof,
160+
address counterparty
161+
) public onlyValidAgreement(proof) returns (T.Agreement memory) {
162+
// retrieve the agreement to storage to inactivate it and return it
163+
T.Agreement memory agreement = getAgreement(proof);
164+
if (agreement.broker != msg.sender) {
165+
revert InvalidAgreementOp("Only broker can settle the agreement.");
166+
}
167+
168+
uint256 fees = agreement.fees; // protocol
169+
uint256 available = agreement.available; // holder earnings
170+
address currency = agreement.currency;
171+
172+
_closeAgreement(proof); // after settled the agreement is complete..
173+
_sumLedgerEntry(address(this), fees, currency);
174+
_registerFundsInTreasury(counterparty, available, currency);
175+
176+
emit AgreementSettled(msg.sender, counterparty, proof);
177+
return agreement;
178+
}
179+
180+
/// @notice Previews an agreement by calculating fees and returning the agreement terms without committing them.
181+
/// @param amount The total amount committed.
182+
/// @param currency The currency used for the agreement.
183+
/// @param broker The authorized account to manage the agreement.
184+
/// @param parties The parties in the agreement.
185+
/// @param payload Additional data for execution.
186+
function previewAgreement(
187+
uint256 amount,
188+
address currency,
189+
address broker,
190+
address[] calldata parties,
191+
bytes calldata payload
192+
) public view returns (T.Agreement memory) {
193+
if (parties.length == 0) {
194+
revert InvalidAgreementOp("Agreement must include at least one party");
195+
}
196+
197+
// agreements transport value..
198+
// imagine an agreement like a bonus, gift card, prepaid card or check..
199+
uint256 deductions = _calcFees(amount, currency);
200+
uint256 available = amount - deductions; // the total after fees
201+
// this design protects the agreement's terms from any future changes in fees or protocol conditions.
202+
// by using this immutable approach, the agreement terms are "frozen" at the time of creation.
203+
return
204+
T.Agreement({
205+
active: true, // the agreement status, true for active, false for closed.
206+
broker: broker, // the authorized account to manage the agreement
207+
currency: currency, // the currency used in transaction
208+
initiator: msg.sender, // the tx initiator
209+
amount: amount, // the transaction amount
210+
fees: deductions, // the protocol fees of the agreement
211+
available: available, // the remaining amount after fees
212+
createdAt: block.timestamp, // the agreement creation time
213+
parties: parties, // the accounts related to agreement
214+
payload: payload // any additional data needed during agreement execution
215+
});
216+
}
217+
218+
/// @dev Authorizes the upgrade of the contract.
219+
/// @notice Only the owner can authorize the upgrade.
220+
/// @param newImplementation The address of the new implementation contract.
221+
function _authorizeUpgrade(address newImplementation) internal override onlyAdmin {}
222+
223+
/// @dev Generates a unique proof for an agreement using keccak256 hashing.
224+
function _createProof(T.Agreement memory agreement) private pure returns (uint256) {
225+
// yes, we can encode full struct as abi.encode with extra overhead..
226+
bytes memory rawProof = abi.encode(agreement);
227+
bytes32 proof = keccak256(rawProof);
228+
return uint256(proof);
229+
}
230+
231+
/// @dev Set the agreement relation with proof in storage.
232+
function _storeAgreement(uint256 proof, T.Agreement memory agreement) private {
233+
_agreements[proof] = agreement; // store agreement..
234+
_actives[agreement.initiator].add(proof);
235+
}
236+
237+
/// @dev Marks an agreement as inactive, effectively closing it.
238+
function _closeAgreement(uint256 proof) private returns (T.Agreement storage) {
239+
// retrieve the agreement to storage to inactivate it and return it
240+
T.Agreement storage agreement = _agreements[proof];
241+
_actives[agreement.initiator].remove(proof);
242+
agreement.active = false;
243+
return agreement;
244+
}
245+
246+
/// @notice Calculates the fee based on the provided total amount and currency.
247+
/// @dev Reverts if the currency is not supported by the fees manager.
248+
/// @param total The total amount from which the fee will be calculated.
249+
/// @param currency The address of the currency for which the fee is being calculated.
250+
function _calcFees(uint256 total, address currency) private view returns (uint256) {
251+
//!IMPORTANT if fees manager does not support the currency, will revert..
252+
uint256 fees = TOLLGATE.getFees(T.Context.RMA, currency);
253+
return total.perOf(fees); // bps repr enforced by tollgate..
254+
}
255+
256+
/// @notice Registers a specified amount of currency in the treasury on behalf of the recipient.
257+
/// @dev This function increases the allowance for the treasury to access the specified `amount` of `currency`
258+
/// and then deposits the funds into the treasury for the given `recipient`.
259+
/// @param recipient The address that will receive the registered funds in the treasury.
260+
/// @param amount The amount of currency to be registered in the treasury.
261+
/// @param currency The address of the ERC20 token used for the registration, or `address(0)` for native currency.
262+
function _registerFundsInTreasury(address recipient, uint256 amount, address currency) private {
263+
// during the closing of the deal the earnings are registered in treasury..
264+
address(TREASURY).increaseAllowance(amount, currency);
265+
TREASURY.deposit(recipient, amount, currency);
266+
}
267+
}

0 commit comments

Comments
 (0)