Skip to content

Commit

Permalink
Website: Reverting change tradeId to tradeData for termination.
Browse files Browse the repository at this point in the history
Merged by EIP-Bot.
  • Loading branch information
cfries authored Aug 8, 2024
1 parent def486b commit f899c81
Show file tree
Hide file tree
Showing 5 changed files with 71 additions and 39 deletions.
47 changes: 32 additions & 15 deletions ERCS/erc-6123.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,9 +65,12 @@ The following methods specify a Smart Derivative Contract's trade initiation and
A party can initiate a trade by providing the party address to trade with, trade data, trade position, payment amount for the trade and initial settlement data. Only registered counterparties are allowed to use that function.

```solidity
function inceptTrade(address withParty, string memory tradeData, int position, int256 paymentAmount, string memory initialSettlementData) external;
function inceptTrade(address withParty, string memory tradeData, int position, int256 paymentAmount, string memory initialSettlementData) external returns (string memory);
```

The position and the paymentAmount are viewed from the incepter.
The function will return a generated unique `tradeId`. The trade id will also be emitted by an event.

#### Trade Initiation Phase: `confirmTrade`

A counterparty can confirm a trade by providing its trade specification data, which then gets matched against the data stored from `inceptTrade` call.
Expand All @@ -76,6 +79,8 @@ A counterparty can confirm a trade by providing its trade specification data, wh
function confirmTrade(address withParty, string memory tradeData, int position, int256 paymentAmount, string memory initialSettlementData) external;
```

Here, the position and the paymentAmount is viewed from the confimer (opposite sign compared to the call to `inceptTrade`).

#### Trade Initiation Phase: `cancelTrade`

The counterparty that called `inceptTrade` has the option to cancel the trade, e.g., in the case where the trade is not confirmed in a timely manner.
Expand Down Expand Up @@ -109,7 +114,7 @@ This might result in a termination or start of the next settlement phase, depend
The transactionData is emitted as part of the corresponding event: `TradeSettled` or `TradeTerminated`

```solidity
function afterTransfer(bool success, uint256 transactionData) external;
function afterTransfer(bool success, string memory transactionData) external;
```


Expand Down Expand Up @@ -162,7 +167,7 @@ event TradeConfirmed(address confirmer, string tradeId);
Emitted on trade cancellation - method 'cancelTrade'

```solidity
event TradeCanceled(address confirmer, string tradeId);
event TradeCanceled(address initiator, string tradeId);
```

#### TradeActivated
Expand All @@ -173,44 +178,63 @@ Emitted when a Trade is activated
event TradeActivated(string tradeId);
```


### SettlementRequested

Emitted when a settlement is requested. May trigger the settlement phase.

```solidity
event SettlementRequested(address initiator, string tradeId, string lastSettlementData);
event SettlementRequested(address initiator, string tradeData, string lastSettlementData);
```

### SettlementEvaluated

Emitted when the settlement phase is started.

```solidity
event SettlementEvaluated();
event SettlementEvaluated(address initiator, int256 settlementAmount, string settlementData);
```

### SettlementTransferred

Emitted when the settlement succeeded.

```solidity
event SettlementTransferred(string transactionData);
```


### SettlementFailed

Emitted when the settlement failed.

```solidity
event SettlementFailed(string transactionData);
```


#### TradeTerminationRequest

Emitted when termination request is initiated by a counterparty

```solidity
event TradeTerminationRequest(address cpAddress, string tradeId, string terminationTerms);
event TradeTerminationRequest(address initiator, string tradeId, int256 terminationPayment, string terminationTerms);
```

#### TradeTerminationConfirmed

Emitted when termination request is confirmed by a counterparty

```solidity
event TradeTerminationConfirmed(address cpAddress, string tradeId, string terminationTerms);
event TradeTerminationConfirmed(address confirmer, string tradeId, int256 terminationPayment, string terminationTerms);
```

#### TradeTerminationCanceled

Emitted when termination request is canceled by the requesting counterparty

```solidity
event TradeTerminationCanceled(address cpAddress, string tradeId, string terminationTerms);
event TradeTerminationCanceled(address initiator, string tradeId, string terminationTerms);
```

#### TradeTerminated
Expand All @@ -221,13 +245,6 @@ Emitted when trade is terminated
event TradeTerminated(string cause);
```

#### ProcessHalted

Emitted when trade processing stops.

```solidity
event ProcessHalted();
```

## Rationale

Expand Down
30 changes: 17 additions & 13 deletions assets/erc-6123/contracts/ISDC.sol
Original file line number Diff line number Diff line change
Expand Up @@ -140,27 +140,29 @@ interface ISDC {

/**
* @dev Emitted when a counterparty proactively requests an early termination of the underlying trade
* @param cpAddress the address of the requesting party
* @param initiator the address of the requesting party
* @param terminationPayment an agreed termination amount (viewed from the requester)
* @param tradeId the trade identifier which is supposed to be terminated
* @param terminationTerms termination terms
*/
event TradeTerminationRequest(address cpAddress, string tradeId, int256 terminationPayment, string terminationTerms);
event TradeTerminationRequest(address initiator, string tradeId, int256 terminationPayment, string terminationTerms);

/**
* @dev Emitted when early termination request is confirmed by the opposite party
* @param cpAddress the party which confirms the trade termination
* @param confirmer the party which confirms the trade termination
* @param tradeId the trade identifier which is supposed to be terminated
* @param terminationPayment an agreed termination amount (viewed from the confirmer, negative of the value provided by the requester)
* @param terminationTerms termination terms
*/
event TradeTerminationConfirmed(address cpAddress, string tradeId, int256 terminationPayment, string terminationTerms);
event TradeTerminationConfirmed(address confirmer, string tradeId, int256 terminationPayment, string terminationTerms);

/**
* @dev Emitted when a counterparty cancels its requests an early termination of the underlying trade
* @param cpAddress the address of the requesting party
* @param initiator the address of the requesting party
* @param tradeId the trade identifier which is supposed to be terminated
* @param terminationTerms termination terms
*/
event TradeTerminationCanceled(address cpAddress, string tradeId, string terminationTerms);
event TradeTerminationCanceled(address initiator, string tradeId, string terminationTerms);

/*------------------------------------------- FUNCTIONALITY ---------------------------------------------------------------------------------------*/

Expand All @@ -174,8 +176,9 @@ interface ISDC {
* @param position is the position the inceptor has in that trade
* @param paymentAmount is the payment amount which can be positive or negative (viewed from the inceptor)
* @param initialSettlementData the initial settlement data (e.g. initial market data at which trade was incepted)
* @return the tradeId uniquely determining this trade.
*/
function inceptTrade(address withParty, string memory tradeData, int position, int256 paymentAmount, string memory initialSettlementData) external;
function inceptTrade(address withParty, string memory tradeData, int position, int256 paymentAmount, string memory initialSettlementData) external returns (string memory);

/**
* @notice Performs a matching of provided trade data and settlement data of a previous trade inception
Expand Down Expand Up @@ -229,26 +232,27 @@ interface ISDC {
/**
* @notice Called from a counterparty to request a mutual termination
* @dev emits a {TradeTerminationRequest}
* @param tradeData a description of the trade specification e.g. in xml format, suggested structure - see assets/eip-6123/doc/sample-tradedata-filestructure.xml
* @param tradeId the trade identifier which is supposed to be terminated
* @param terminationPayment an agreed termination amount (viewed from the requester)
* @param terminationTerms the termination terms to be stored on chain.
*/
function requestTradeTermination(string memory tradeData, int256 terminationPayment, string memory terminationTerms) external;
function requestTradeTermination(string memory tradeId, int256 terminationPayment, string memory terminationTerms) external;

/**
* @notice Called from a party to confirm an incepted termination, which might trigger a final settlement before trade gets closed
* @dev emits a {TradeTerminationConfirmed}
* @param tradeData a description of the trade specification e.g. in xml format, suggested structure - see assets/eip-6123/doc/sample-tradedata-filestructure.xml
* @param tradeId the trade identifier which is supposed to be terminated
* @param terminationPayment an agreed termination amount (viewed from the confirmer, negative of the value provided by the requester)
* @param terminationTerms the termination terms to be stored on chain.
*/
function confirmTradeTermination(string memory tradeData, int256 terminationPayment, string memory terminationTerms) external;
function confirmTradeTermination(string memory tradeId, int256 terminationPayment, string memory terminationTerms) external;

/**
* @notice Called from a party to confirm an incepted termination, which might trigger a final settlement before trade gets closed
* @dev emits a {TradeTerminationCanceled}
* @param tradeData a description of the trade specification e.g. in xml format, suggested structure - see assets/eip-6123/doc/sample-tradedata-filestructure.xml
* @param tradeId the trade identifier which is supposed to be terminated
* @param terminationPayment an agreed termination amount (viewed from the requester)
* @param terminationTerms the termination terms
*/
function cancelTradeTermination(string memory tradeData, int256 terminationPayment, string memory terminationTerms) external;
function cancelTradeTermination(string memory tradeId, int256 terminationPayment, string memory terminationTerms) external;
}
11 changes: 7 additions & 4 deletions assets/erc-6123/contracts/SDCSingleTrade.sol
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ abstract contract SDCSingleTrade is ISDC {
* emits a TradeIncepted
* can be called only when TradeState = Incepted
*/
function inceptTrade(address _withParty, string memory _tradeData, int _position, int256 _paymentAmount, string memory _initialSettlementData) external override onlyCounterparty onlyWhenTradeInactive {
function inceptTrade(address _withParty, string memory _tradeData, int _position, int256 _paymentAmount, string memory _initialSettlementData) external override onlyCounterparty onlyWhenTradeInactive returns (string memory) {
require(msg.sender != _withParty, "Calling party cannot be the same as withParty");
require(_position == 1 || _position == -1, "Position can only be +1 or -1");
tradeState = TradeState.Incepted; // Set TradeState to Incepted
Expand All @@ -144,6 +144,7 @@ abstract contract SDCSingleTrade is ISDC {
tradeID = Strings.toString(transactionHash);
tradeData = _tradeData; // Set trade data to enable querying already in inception state
emit TradeIncepted(msg.sender, _withParty, tradeID, _tradeData, _position, _paymentAmount, _initialSettlementData);
return tradeID;
}

/*
Expand Down Expand Up @@ -189,8 +190,7 @@ abstract contract SDCSingleTrade is ISDC {
require(keccak256(abi.encodePacked(tradeID)) == keccak256(abi.encodePacked(_tradeId)), "Trade ID mismatch");
uint256 hash = uint256(keccak256(abi.encode(_tradeId, "terminate", _terminationPayment, terminationTerms)));
pendingRequests[hash] = msg.sender;
terminationPayment = _terminationPayment; // termination payment will be provided in view of receiving party
emit TradeTerminationRequest(msg.sender, _tradeId, terminationPayment, terminationTerms);
emit TradeTerminationRequest(msg.sender, _tradeId, _terminationPayment, terminationTerms);
}

/*
Expand All @@ -203,7 +203,10 @@ abstract contract SDCSingleTrade is ISDC {
uint256 hashConfirm = uint256(keccak256(abi.encode(_tradeId, "terminate", -_terminationPayment, terminationTerms)));
require(pendingRequests[hashConfirm] == pendingRequestParty, "Confirmation of termination failed due to wrong party or missing request");
delete pendingRequests[hashConfirm];
emit TradeTerminationConfirmed(msg.sender, _tradeId, terminationPayment, terminationTerms);

terminationPayment = msg.sender == receivingParty ? _terminationPayment : -_terminationPayment; // termination payment will be provided in view of receiving party

emit TradeTerminationConfirmed(msg.sender, _tradeId, _terminationPayment, terminationTerms);
/* Trigger Termination Payment Amount */
address payerAddress = terminationPayment > 0 ? otherParty(receivingParty) : receivingParty;
uint256 absPaymentAmount = uint256(abs(_terminationPayment));
Expand Down
2 changes: 1 addition & 1 deletion assets/erc-6123/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@finmath.net/sdc",
"version": "0.4.0",
"version": "0.4.2",
"description": "Solidity Smart Derivative Contracts",
"author": "Christian Fries, Peter Kohl-Landgraf, Alexandros Korpis",
"license": "ISC",
Expand Down
20 changes: 14 additions & 6 deletions assets/erc-6123/test/SDCTests.js
Original file line number Diff line number Diff line change
Expand Up @@ -208,34 +208,42 @@ describe("Livecycle Unit-Tests for SDC Plege Balance", () => {
await token.connect(counterparty1).mint(counterparty1.address,initialLiquidityBalance);
await token.connect(counterparty2).mint(counterparty2.address,initialLiquidityBalance);
let sdc = await SDCFactory.deploy(counterparty1.address, counterparty2.address,token.address,marginBufferAmount,terminationFee);
// Note: position = 1 => counterparty1 is the receivingParty
const incept_call = await sdc.connect(counterparty1).inceptTrade(counterparty2.address, trade_data, 1, 0, "initialMarketData");
const receipt = await incept_call.wait();
const event = receipt.events.find(event => event.event === 'TradeIncepted');
const trade_id = event.args[2];
const confirm_call = await sdc.connect(counterparty2).confirmTrade(counterparty1.address, trade_data, -1, 0, "initialMarketData");

// Note: terminationPayment is considered to be viewed from the requester here.
const terminate_call = await sdc.connect(counterparty2).requestTradeTermination(trade_id, -terminationPayment, "terminationTerms");
// Note: terminationPayment is considered to be viewed from the confirmer here.
const confirm_terminate_call = await sdc.connect(counterparty1).confirmTradeTermination(trade_id, +terminationPayment, "terminationTerms");

let cp1_balance = await token.connect(counterparty1).balanceOf(counterparty1.address);
let cp2_balance = await token.connect(counterparty1).balanceOf(counterparty2.address);
await expect(cp1_balance).equal(initialLiquidityBalance-terminationPayment);
await expect(cp2_balance).equal(initialLiquidityBalance+terminationPayment);
await expect(cp1_balance).equal(initialLiquidityBalance+terminationPayment);
await expect(cp2_balance).equal(initialLiquidityBalance-terminationPayment);
});

it("9b. CP1 is Receiving Party, Trade-Termination is incepted by CP1 which pays the termination payment to CP2", async () => {
let token = await ERC20Factory.deploy();
await token.connect(counterparty1).mint(counterparty1.address,initialLiquidityBalance);
await token.connect(counterparty2).mint(counterparty2.address,initialLiquidityBalance);
let sdc = await SDCFactory.deploy(counterparty1.address, counterparty2.address,token.address,marginBufferAmount,terminationFee);
// Note: position = 1 => counterparty1 is the receivingParty
const incept_call = await sdc.connect(counterparty1).inceptTrade(counterparty2.address, trade_data, 1, 0, "initialMarketData");
const receipt = await incept_call.wait();
const event = receipt.events.find(event => event.event === 'TradeIncepted');
const trade_id = event.args[2];
const confirm_call = await sdc.connect(counterparty2).confirmTrade(counterparty1.address, trade_data, -1, 0, "initialMarketData");
const terminate_call = await sdc.connect(counterparty1).requestTradeTermination(trade_id, -terminationPayment, "terminationTerms");
const confirm_terminate_call = await sdc.connect(counterparty2).confirmTradeTermination(trade_id, +terminationPayment, "terminationTerms");
// Note: terminationPayment is considered to be viewed from the requester here.
const terminate_call = await sdc.connect(counterparty1).requestTradeTermination(trade_id, terminationPayment, "terminationTerms");
const confirm_terminate_call = await sdc.connect(counterparty2).confirmTradeTermination(trade_id, -terminationPayment, "terminationTerms");
let cp1_balance = await token.connect(counterparty1).balanceOf(counterparty1.address);
let cp2_balance = await token.connect(counterparty1).balanceOf(counterparty2.address);
await expect(cp1_balance).equal(initialLiquidityBalance-terminationPayment);
await expect(cp2_balance).equal(initialLiquidityBalance+terminationPayment);
await expect(cp1_balance).equal(initialLiquidityBalance+terminationPayment);
await expect(cp2_balance).equal(initialLiquidityBalance-terminationPayment);
});

it("10. Successful Inception with Upfront transferred from CP2 to CP1 + successful settlement transferred from CP1 to CP2", async () => {
Expand Down

0 comments on commit f899c81

Please sign in to comment.