-
Notifications
You must be signed in to change notification settings - Fork 460
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Add ERC: Interest Rate Swaps * Create erc-xxxx.md * Update erc-template.md * interface functions * Update ERCS/erc-xxxx.md Co-authored-by: Andrew B Coathup <[email protected]> * Update erc-xxxx.md * update comments * small fix * expressing the benchmark in uint8 * Update erc-xxxx.md * add motivation section * Update the specification * Update ERCS/erc-xxxx.md Co-authored-by: Andrew B Coathup <[email protected]> * Rename erc-xxxx.md to erc-7586.md * Shorten the description * minor fix * rename fixedRate to swapRate * requires ERC721 * update terminologies * update the rationale section * fix link * Update spec * update spec * swap param tokenization * minor fix * backwards compatibility section * add the security consideration section * minor fix * fix * small fix * exclude ERC721 inheritance * add `isActive` and `terminateSwap` functions * add `agree` function * minor fix * fix * add TerminateSwap event * small fix * change return type for benchmark * minor fix -remove isActive function * Create ERC7586.sol * Update ERC7586.sol * Create ERC20.sol * Update ERC20.sol * Create IERC20.sol * Update IERC20.sol * Update ERC20.sol * add reference implementation * Update erc-7586.md * Update erc-7586.md * change status * Update ERC20.sol * Update ERC7586.sol * Update ERCS/erc-7586.md Co-authored-by: Sam Wilson <[email protected]> * Update ERCS/erc-7586.md Co-authored-by: Sam Wilson <[email protected]> * Update ERCS/erc-7586.md Co-authored-by: Sam Wilson <[email protected]> * Update ERCS/erc-7586.md Co-authored-by: Sam Wilson <[email protected]> * Update ERCS/erc-7586.md Co-authored-by: Sam Wilson <[email protected]> * Update ERCS/erc-7586.md Co-authored-by: Sam Wilson <[email protected]> * Update ERCS/erc-7586.md Co-authored-by: Sam Wilson <[email protected]> * Update ERCS/erc-7586.md Co-authored-by: Sam Wilson <[email protected]> * Update ERCS/erc-7586.md Co-authored-by: Sam Wilson <[email protected]> * Update erc-7586.md * Update erc-7586.md * Update erc-7586.md * Update erc-7586.md * updates rates name and adds rateDecimals function * Create IERC7586.sol * Update ERC7586.sol * Update ERC20.sol * Update ERC20.sol * add irs img * add img * Update erc-7586.md * fix link --------- Co-authored-by: Andrew B Coathup <[email protected]> Co-authored-by: Sam Wilson <[email protected]>
- Loading branch information
1 parent
87cd120
commit 9d4c3b3
Showing
6 changed files
with
648 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,183 @@ | ||
--- | ||
eip: 7586 | ||
title: Interest Rate Swaps | ||
description: Interest rate swaps derivative contracts | ||
author: Samuel Gwlanold Edoumou (@Edoumou) | ||
discussions-to: https://ethereum-magicians.org/t/interest-rate-swaps/17777 | ||
status: Draft | ||
type: Standards Track | ||
category: ERC | ||
created: 2023-12-31 | ||
requires: 20, 165 | ||
--- | ||
|
||
## Abstract | ||
|
||
This proposal introduces a standardized framework for on-chain interest rate swaps. The proposed standard aims to facilitate the seamless exchange of fixed and floating interest rate cash flows between parties, providing a foundation for decentralized finance (DeFi) applications. | ||
|
||
## Motivation | ||
|
||
Interest Rate Swapping (IRS) denotes a derivative contract wherein two parties mutually consent to exchange a series of forthcoming interest payments based on a specified notional amount. This financial instrument serves as a strategic tool for hedging against interest rate fluctuations. The mechanism entails the utilization of a benchmark index to facilitate the exchange between a variable interest rate and a fixed rate. Despite its widespread use, there is currently an absence of a standardized framework that enables the representation of IRS contracts on blockchain platforms. | ||
|
||
This proposal addresses this gap by establishing a consistent and transparent methodology for representing IRS contracts within the blockchain environment. By doing so, it would enhance the interoperability, security, and efficiency of interest rate swap transactions on distributed ledger technology. | ||
|
||
## Specification | ||
|
||
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119 and RFC 8174. | ||
|
||
### Example Flow | ||
|
||
![alt text](../assets/eip-7586/irs.jpeg "IRS diagram") | ||
|
||
Every contract compliant with this ERC MUST implement the following interface. The contract MUST inherit from [`ERC20`](./eip-20) to tokenize the swap cash flows. | ||
|
||
```solidity | ||
pragma solidity ^0.8.0; | ||
/** | ||
* @title ERC-7586 Interest Rate Swaps | ||
*/ | ||
interface IERC7586 /** is ERC20, ERC165 */ { | ||
// events | ||
/** | ||
* @notice MUST be emitted when interest rates are swapped | ||
* @param _amount the interest difference to be transferred | ||
* @param _account the recipient account to send the interest difference to. MUST be either the `payer` or the `receiver` | ||
*/ | ||
event Swap(uint256 _amount, address _account); | ||
/** | ||
* @notice MUST be emitted when the swap contract is terminated | ||
* @param _payer the swap payer | ||
* @param _receiver the swap receiver | ||
*/ | ||
event TerminateSwap(address indexed _payer, address indexed _receiver); | ||
// functions | ||
/** | ||
* @notice Returns the IRS `payer` account address. The party who agreed to pay fixed interest | ||
*/ | ||
function fixedInterestPayer() external view returns(address); | ||
/** | ||
* @notice Returns the IRS `receiver` account address. The party who agreed to pay floating interest | ||
*/ | ||
function floatingInterestPayer() external view returns(address); | ||
/** | ||
* @notice Returns the number of decimals the swap rate and spread use - e.g. `4` means to divide the rates by `10000` | ||
* To express the interest rates in basis points unit, the decimal MUST be equal to `2`. This means rates MUST be divided by `100` | ||
* 1 basis point = 0.01% = 0.0001 | ||
* ex: if interest rate = 2.5%, then swapRate() => 250 `basis points` | ||
*/ | ||
function ratesDecimals() external view returns(uint8); | ||
/** | ||
* @notice Returns the fixed interest rate | ||
*/ | ||
function swapRate() external view returns(uint256); | ||
/** | ||
* @notice Returns the floating rate spread, i.e. the fixed part of the floating interest rate | ||
* | ||
* floatingRate = benchmark + spread | ||
*/ | ||
function spread() external view returns(uint256); | ||
/** | ||
* @notice Returns the contract address of the asset to be transferred when swapping IRS. Depending on what the two parties agreed upon, this could be a currency, etc. | ||
* Example: If the two parties agreed to swap interest rates in USDC, then this function should return the USDC contract address. | ||
* This address SHOULD be used in the `swap` function to transfer the interest difference to either the `payer` or the `receiver`. Example: IERC(assetContract).transfer | ||
*/ | ||
function assetContract() external view returns(address); | ||
/** | ||
* @notice Returns the notional amount in unit of asset to be transferred when swapping IRS. This amount serves as the basis for calculating the interest payments, and may not be exchanged | ||
* Example: If the two parties aggreed to swap interest rates in USDC, then the notional amount may be equal to 1,000,000 USDC | ||
*/ | ||
function notionalAmount() external view returns(uint256); | ||
/** | ||
* @notice Returns the interest payment frequency | ||
*/ | ||
function paymentFrequency() external view returns(uint256); | ||
/** | ||
* @notice Returns an array of specific dates on which the interest payments are exchanged. Each date MUST be a Unix timestamp like the one returned by block.timestamp | ||
* The length of the array returned by this function MUST equal the total number of swaps that should be realized | ||
* | ||
* OPTIONAL | ||
*/ | ||
function paymentDates() external view returns(uint256[] memory); | ||
/** | ||
* @notice Returns the starting date of the swap contract. This is a Unix Timestamp like the one returned by block.timestamp | ||
*/ | ||
function startingDate() external view returns(uint256); | ||
/** | ||
* @notice Returns the maturity date of the swap contract. This is a Unix Timestamp like the one returned by block.timestamp | ||
*/ | ||
function maturityDate() external view returns(uint256); | ||
/** | ||
* @notice Returns the benchmark in basis point unit | ||
* Example: value of one the following rates: CF BIRC, EURIBOR, HIBOR, SHIBOR, SOFR, SONIA, TONAR, etc. | ||
*/ | ||
function benchmark() external view returns(uint256); | ||
/** | ||
* @notice Returns the oracle contract address for the benchmark rate, or the zero address when the two parties agreed to set the benchmark manually. | ||
* This contract SHOULD be used to fetch real time benchmark rate | ||
* Example: Contract address for `CF BIRC` | ||
* | ||
* OPTIONAL. The two parties MAY agree to set the benchmark manually | ||
*/ | ||
function oracleContractForBenchmark() external view returns(address); | ||
/** | ||
* @notice Makes swap calculation and transfers the interest difference to either the `payer` or the `receiver` | ||
*/ | ||
function swap() external returns(bool); | ||
/** | ||
* @notice Terminates the swap contract before its maturity date. MUST be called by either the `payer`or the `receiver`. | ||
*/ | ||
function terminateSwap() external; | ||
} | ||
``` | ||
### Tokenization of Swap Cash Flows | ||
|
||
The interest payments associated with the IRS MUST be tokenized by issuing digital [ERC-20](./eip-20) tokens to the respective parties according to the terms of the swap. Each token SHOULD represent a specific interest payment. Every time a swap happens (the `swap` function is called), one token MUST be burned from each party. | ||
|
||
## Rationale | ||
|
||
This standard allows parties involved in the IRS contract to define essential parameters such as notional amount, interest rates, payment frequency, and payment dates. This flexibility accommodates a diverse range of financial agreements, catering to the unique needs of different participants. | ||
|
||
To accommodate a wide array of use cases, the standard introduces optional features such as payment dates and manual benchmark setting. This allows parties to tailor the contract to specific requirements, while maintaining a core set of functions for essential functionality. | ||
|
||
To ensure real-time and accurate benchmark rates, the standard integrates with oracles. Parties have the option to use oracles for fetching benchmark rates, enhancing the reliability and accuracy of interest rate calculations. | ||
|
||
## Backwards Compatibility | ||
|
||
This standard is backward compatible with ERC-20. | ||
|
||
## Reference Implementation | ||
|
||
The complete reference implementation can be found [here](../assets/eip-7586/ERC7586.sol). | ||
|
||
This reference implementation serves as a foundation for the implementation of more advanced types of swaps. | ||
|
||
## Security Considerations | ||
|
||
Security considerations of various types must be thoroughly evaluated | ||
|
||
* Interest Rate Risk: This pertains to the potential impact of fluctuations in interest rates. | ||
* Credit Risk: There exists the possibility that one or both parties may default on their respective responsibilities. | ||
* ERC-20 Risks: All security aspects outlined in the ERC-20 standard must be taken into account. | ||
|
||
Both parties must acknowledge their awareness of these security risks before proceeding with the implementation of the standard. | ||
|
||
## Copyright | ||
|
||
Copyright and related rights waived via [CC0](../LICENSE.md). |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,124 @@ | ||
// SPDX-License-Identifier: CC0-1.0 | ||
pragma solidity ^0.8.0; | ||
|
||
import "./IERC7586.sol"; | ||
import "./Tokens/ERC20.sol"; | ||
|
||
contract ERC7586 is IERC7586, ERC20 { | ||
constructor(string memory _name, string memory _symbol, IRS memory _irs) ERC20(_name, _symbol) { | ||
irsSymbol = _symbol; | ||
irs = _irs; | ||
|
||
_isActive = true; | ||
|
||
_balanceOf[_irs.payer] = _irs.paymentDates.length * 1 ether; | ||
_balanceOf[_irs.receiver] = _irs.paymentDates.length * 1 ether; | ||
_totalSupply = _irs.paymentDates.length * 2 * 1 ether; | ||
} | ||
|
||
function fixedInterestPayer() external view returns(address) { | ||
return irs.payer; | ||
} | ||
|
||
function floatingInterestPayer() external view returns(address) { | ||
return irs.receiver; | ||
} | ||
|
||
function ratesDecimals() external view returns(uint8) { | ||
return irs.ratesDecimals; | ||
} | ||
|
||
function swapRate() external view returns(uint256) { | ||
return irs.swapRate; | ||
} | ||
|
||
function spread() external view returns(uint256) { | ||
return irs.spread; | ||
} | ||
|
||
function assetContract() external view returns(address) { | ||
return irs.assetContract; | ||
} | ||
|
||
function notionalAmount() external view returns(uint256) { | ||
return irs.notionalAmount; | ||
} | ||
|
||
function paymentFrequency() external view returns(uint256) { | ||
return irs.paymentFrequency; | ||
} | ||
|
||
function paymentDates() external view returns(uint256[] memory) { | ||
return irs.paymentDates; | ||
} | ||
|
||
function startingDate() external view returns(uint256) { | ||
return irs.startingDate; | ||
} | ||
|
||
function maturityDate() external view returns(uint256) { | ||
return irs.maturityDate; | ||
} | ||
|
||
function benchmark() external view returns(uint256) { | ||
// This should be fetched from an oracle contract | ||
return irs.benchmark; | ||
} | ||
|
||
function oracleContractForBenchmark() external view returns(address) { | ||
return irs.oracleContractForBenchmark; | ||
} | ||
|
||
function isActive() public view returns(bool) { | ||
return _isActive; | ||
} | ||
|
||
function swap() external returns(bool) { | ||
require(_isActive, "Contract not Active"); | ||
require(_hasAgreed[irs.payer], "Missing Agreement"); | ||
require(_hasAgreed[irs.receiver], "Missing Agreement"); | ||
|
||
uint256 fixedRate = irs.swapRate; | ||
uint256 floatingRate = irs.benchmark + irs.spread; | ||
uint256 notional = irs.notionalAmount; | ||
|
||
uint256 fixedInterest = notional * fixedRate; | ||
uint256 floatingInterest = notional * floatingRate; | ||
|
||
uint256 interestToTransfer; | ||
address _recipient; | ||
address _payer; | ||
|
||
if(fixedInterest == floatingInterest) { | ||
revert("Nothing to swap"); | ||
} else if(fixedInterest > floatingInterest) { | ||
interestToTransfer = fixedInterest - floatingInterest; | ||
_recipient = irs.receiver; | ||
_payer = irs.payer; | ||
} else { | ||
interestToTransfer = floatingInterest - fixedInterest; | ||
_recipient = irs.payer; | ||
_payer = irs.receiver; | ||
} | ||
|
||
burn(irs.payer, 1 ether); | ||
burn(irs.receiver, 1 ether); | ||
|
||
uint256 _paymentCount = paymentCount; | ||
paymentCount = _paymentCount + 1; | ||
|
||
IERC20(irs.assetContract).transferFrom(_payer, _recipient, interestToTransfer * 1 ether / 10_000); | ||
|
||
if(paymentCount == irs.paymentDates.length) { | ||
_isActive = false; | ||
} | ||
|
||
return true; | ||
} | ||
|
||
function terminateSwap() external { | ||
require(_isActive, "Contract not Active"); | ||
|
||
_isActive = false; | ||
} | ||
} |
Oops, something went wrong.