Created
August 27, 2024 18:06
-
-
Save RadNi/703def6ae3f927392056024f57b30362 to your computer and use it in GitHub Desktop.
An implementation of atomic swaps in the async programing model
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
pragma solidity ^0.8.0; | |
import "./Nil.sol"; | |
/* | |
An implementation of atomic swaps in the async programing model | |
*/ | |
contract Swap is NilBase{ | |
// Any instance of swap requests are held in an `escrow` struct | |
struct escrow { | |
mapping(uint256 => Nil.Token) firstDebtTokens; // The first party's tokens to be deposited | |
mapping(uint256 => Nil.Token) secondDebtTokens; // The second party's tokens to be deposited | |
mapping(uint256 => uint256) firstAmounts; // The amount of each token that the first party has already deposited | |
mapping(uint256 => uint256) secondAmounts; // The amount of each token that the second party has already deposited | |
uint256 firstTokensSize; // Number of tokens to be deposited by the first party | |
uint256 secondTokensSize; // Number of tokens to be deposited by the second party | |
address firstParty; // First party's address | |
address secondParty; // Second party's address | |
bool isValid; // It's set to false if the escrow doesn't exist, or it's already finalized | |
} | |
mapping(uint256 => escrow) public requests; | |
uint256 public counter = 0; | |
event NewEscrow(uint256 indexed reqId, address indexed, address indexed); | |
event Deposit(uint256 indexed reqId, bool indexed party, uint256 tokenId, uint256 amount); | |
event SwapFinalized(uint256 indexed reqId, address indexed first, address indexed second); | |
// A swap request can be initiated by everyone. It determines parties addresses, the tokens involved in each side of the swap along with their required values. | |
// Note that, one should send tokens to this function. | |
// Upon successful registration, it emits a `NewEscrow` log | |
function newRequest( | |
address first, address second, | |
uint256[] memory debtsFirstIds, uint256[] memory debtsFirstAmount, | |
uint256[] memory debtsSecondIds, uint256[] memory debtsSecondAmount | |
) public returns (uint256){ | |
require(debtsFirstIds.length == debtsFirstAmount.length, "array lengths do not match!"); | |
require(debtsSecondIds.length == debtsSecondAmount.length, "array lengths do not match!"); | |
// filling in the request's data | |
counter += 1; | |
requests[counter].isValid = true; | |
requests[counter].firstParty = first; | |
requests[counter].secondParty = second; | |
requests[counter].firstTokensSize = debtsFirstIds.length; | |
requests[counter].secondTokensSize = debtsSecondIds.length; | |
// filling in the tokens' data | |
for (uint256 i = 0; i < debtsFirstIds.length; i++) { | |
requests[counter].firstAmounts[debtsFirstIds[i]] = 0; | |
requests[counter].firstDebtTokens[i].id = debtsFirstIds[i]; | |
requests[counter].firstDebtTokens[i].amount = debtsFirstAmount[i]; | |
} | |
for (uint256 i = 0; i < debtsSecondIds.length; i++) { | |
requests[counter].secondAmounts[debtsFirstIds[i]] = 0; | |
requests[counter].secondDebtTokens[i].id = debtsSecondIds[i]; | |
requests[counter].secondDebtTokens[i].amount = debtsSecondAmount[i]; | |
} | |
// emit log and return the request id | |
emit NewEscrow(counter, first, second); | |
return counter; | |
} | |
// is used to deposit tokens into a particular escrow | |
function deposit(uint256 reqId, bool party) public { | |
require(requests[reqId].isValid, "Escrow doesn't exist!"); | |
Nil.Token[] memory tokens = Nil.msgTokens(); | |
for (uint256 i = 0; i < tokens.length; i++) { | |
if (party) { // First party | |
requests[reqId].firstAmounts[tokens[i].id] += tokens[i].amount; | |
} else { // Second party | |
requests[reqId].secondAmounts[tokens[i].id] += tokens[i].amount; | |
} | |
emit Deposit(reqId, party, tokens[i].id, tokens[i].amount); | |
} | |
} | |
// once all the required tokens are fulfilled, everyone can finalize the swap which sends out the exchanged values to either parties | |
function finalize(uint256 reqId) public { | |
require(requests[reqId].isValid, "Escrow doesn't exist!"); | |
for (uint256 index = 0; index < requests[reqId].firstTokensSize; index++) { | |
uint256 max = requests[reqId].firstDebtTokens[index].amount; | |
uint256 tId = requests[reqId].firstDebtTokens[index].id; | |
uint256 amount = requests[reqId].firstAmounts[tId]; | |
require(amount >= max, "request not fulfiled on the first side yet!"); | |
} | |
for (uint256 index = 0; index < requests[reqId].secondTokensSize; index++) { | |
uint256 max = requests[reqId].secondDebtTokens[index].amount; | |
uint256 tId = requests[reqId].secondDebtTokens[index].id; | |
uint256 amount = requests[reqId].secondAmounts[tId]; | |
require(amount >= max, "request not fulfiled on the second side yet!"); | |
} | |
requests[reqId].isValid = false; | |
Nil.Token[] memory firstTokens = new Nil.Token[] (requests[reqId].firstTokensSize); | |
Nil.Token[] memory secondTokens = new Nil.Token[] (requests[reqId].secondTokensSize); | |
for (uint256 index = 0; index < requests[reqId].firstTokensSize; index++) { | |
firstTokens[index].amount = requests[reqId].secondDebtTokens[index].amount; | |
firstTokens[index].id = requests[reqId].secondDebtTokens[index].id; | |
} | |
for (uint256 index = 0; index < requests[reqId].secondTokensSize; index++) { | |
secondTokens[index].amount = requests[reqId].firstDebtTokens[index].amount; | |
secondTokens[index].id = requests[reqId].firstDebtTokens[index].id; | |
} | |
Nil.asyncCall( | |
requests[reqId].firstParty, | |
address(0), | |
address(0), | |
50, | |
1, | |
false, | |
0, | |
secondTokens, | |
"" | |
); | |
Nil.asyncCall( | |
requests[reqId].secondParty, | |
address(0), | |
address(0), | |
50, | |
1, | |
false, | |
0, | |
firstTokens, | |
"" | |
); | |
emit SwapFinalized(reqId, requests[reqId].firstParty, requests[reqId].secondParty); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment