Skip to content

Commit

Permalink
Add withdrawfutureswap
Browse files Browse the repository at this point in the history
  • Loading branch information
Bushstar committed Mar 24, 2022
1 parent fbe4bd9 commit 2a137e5
Show file tree
Hide file tree
Showing 8 changed files with 429 additions and 50 deletions.
8 changes: 8 additions & 0 deletions src/masternodes/accounts.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -113,3 +113,11 @@ void CAccountsView::ForEachFuturesUserValues(std::function<bool(const CFuturesUs
ForEach<ByFuturesKey, CFuturesUserKey, CFuturesUserValue>(callback, start);
}

Res CAccountsView::EraseFuturesUserValues(const CFuturesUserKey& key)
{
if (!EraseBy<ByFuturesKey>(key)) {
return Res::Err("Failed to erase futures");
}

return Res::Ok();
}
5 changes: 5 additions & 0 deletions src/masternodes/accounts.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@ struct CFuturesUserKey {
READWRITE(WrapBigEndian(txn_));
}
}

bool operator<(const CFuturesUserKey& o) const {
return std::tie(height, owner, txn) < std::tie(o.height, o.owner, o.txn);
}
};

struct CFuturesUserValue {
Expand Down Expand Up @@ -66,6 +70,7 @@ class CAccountsView : public virtual CStorageView
Res UpdateBalancesHeight(CScript const & owner, uint32_t height);

Res StoreFuturesUserValues(const CFuturesUserKey& key, const CFuturesUserValue& futures);
Res EraseFuturesUserValues(const CFuturesUserKey& key);
void ForEachFuturesUserValues(std::function<bool(const CFuturesUserKey&, const CFuturesUserValue&)> callback, const CFuturesUserKey& start = {});

// tags
Expand Down
2 changes: 2 additions & 0 deletions src/masternodes/balances.h
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,7 @@ struct CDFIP2203Message {
CScript owner;
CTokenAmount source{};
uint32_t destination{};
bool withdraw{};

ADD_SERIALIZE_METHODS;

Expand All @@ -236,6 +237,7 @@ struct CDFIP2203Message {
READWRITE(owner);
READWRITE(source);
READWRITE(destination);
READWRITE(withdraw);
}
};

Expand Down
78 changes: 65 additions & 13 deletions src/masternodes/mn_checks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1532,23 +1532,75 @@ class CCustomTxApplyVisitor : public CCustomTxVisitor
return Res::Err("Failed to get smart contract address from chainparams");
}

CTxDestination dest;
ExtractDestination(contractAddress, dest);
CDataStructureV0 liveKey{AttributeTypes::Live, ParamIDs::Economy, EconomyKeys::DFIP2203Tokens};
auto balances = attributes->GetValue(liveKey, CBalances{});

auto res = TransferTokenBalance(obj.source.nTokenId, obj.source.nValue, obj.owner, contractAddress);
if (!res) {
return res;
}
if (obj.withdraw) {
const auto blockPeriod = attributes->GetValue(blockKey, CAmount{});
const uint32_t startHeight = height - (height % blockPeriod);
std::map<CFuturesUserKey, CFuturesUserValue> userFuturesValues;

res = mnview.StoreFuturesUserValues({height, obj.owner, txn}, {obj.source, obj.destination});
if (!res) {
return res;
}
mnview.ForEachFuturesUserValues([&](const CFuturesUserKey& key, const CFuturesUserValue& futuresValues) {
if (key.height <= startHeight) {
return false;
}

CDataStructureV0 liveKey{AttributeTypes::Live, ParamIDs::Economy, EconomyKeys::DFIP2203Tokens};
auto balances = attributes->GetValue(liveKey, CBalances{});
if (source->symbol == "DUSD") {
if (key.owner == obj.owner && futuresValues.destination == obj.destination) {
userFuturesValues[key] = futuresValues;
}
} else {
if (key.owner == obj.owner && futuresValues.source.nTokenId == obj.source.nTokenId) {
userFuturesValues[key] = futuresValues;
}
}

return true;
}, {height, obj.owner, std::numeric_limits<uint32_t>::max()});

CTokenAmount totalFutures{};
totalFutures.nTokenId = obj.source.nTokenId;

for (const auto& [key, value] : userFuturesValues) {
totalFutures.Add(value.source.nValue);
mnview.EraseFuturesUserValues(key);
}

auto res = totalFutures.Sub(obj.source.nValue);
if (!res) {
return res;
}

if (totalFutures.nValue > 0) {
auto res = mnview.StoreFuturesUserValues({height, obj.owner, txn}, {totalFutures, obj.destination});
if (!res) {
return res;
}
}

res = TransferTokenBalance(obj.source.nTokenId, obj.source.nValue, contractAddress, obj.owner);
if (!res) {
return res;
}

res = balances.Sub(CTokenAmount{obj.source.nTokenId, obj.source.nValue});
if (!res) {
return res;
}
} else {
auto res = TransferTokenBalance(obj.source.nTokenId, obj.source.nValue, obj.owner, contractAddress);
if (!res) {
return res;
}

res = mnview.StoreFuturesUserValues({height, obj.owner, txn}, {obj.source, obj.destination});
if (!res) {
return res;
}

balances.Add(CTokenAmount{obj.source.nTokenId, obj.source.nValue});
}

balances.Add(CTokenAmount{obj.source.nTokenId, obj.source.nValue});
attributes->attributes[liveKey] = balances;

mnview.SetVariable(*attributes);
Expand Down
89 changes: 87 additions & 2 deletions src/masternodes/rpc_accounts.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2112,6 +2112,90 @@ UniValue futureswap(const JSONRPCRequest& request) {
return signsend(rawTx, pwallet, optAuthTx)->GetHash().GetHex();
}


UniValue withdrawfutureswap(const JSONRPCRequest& request) {
auto pwallet = GetWallet(request);

RPCHelpMan{"withdrawfutureswap",
"\nCreates and submits to the network a withdrawl from futures contract transaction.\n"
" Withdrawal will be back to the address specified in the futures contract." +
HelpRequiringPassphrase(pwallet) + "\n",
{
{"address", RPCArg::Type::STR, RPCArg::Optional::NO, "Address used to fund contract with"},
{"amount", RPCArg::Type::STR, RPCArg::Optional::NO, "Amount to withdraw in amount@token format"},
{"destination", RPCArg::Type::NUM, RPCArg::Optional::OMITTED_NAMED_ARG, "The dToken if DUSD supplied"},
{"inputs", RPCArg::Type::ARR, RPCArg::Optional::OMITTED_NAMED_ARG,
"A json array of json objects",
{
{"", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "",
{
{"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction id"},
{"vout", RPCArg::Type::NUM, RPCArg::Optional::NO, "The output number"},
},
},
},
},
},
RPCResult{
"\"hash\" (string) The hex-encoded hash of broadcasted transaction\n"
},
RPCExamples{
HelpExampleCli("futureswap", "dLb2jq51qkaUbVkLyCiVQCoEHzRSzRPEsJ 1000@TSLA")
+ HelpExampleRpc("futureswap", "dLb2jq51qkaUbVkLyCiVQCoEHzRSzRPEsJ, 1000@TSLA")
},
}.Check(request);

if (pwallet->chain().isInitialBlockDownload()) {
throw JSONRPCError(RPC_CLIENT_IN_INITIAL_DOWNLOAD, "Cannot create transactions while still in Initial Block Download");
}
pwallet->BlockUntilSyncedToCurrentChain();

const auto dest = DecodeDestination(request.params[0].getValStr());
if (!IsValidDestination(dest)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid address");
}

CDFIP2203Message msg{};
msg.owner = GetScriptForDestination(dest);
msg.source = DecodeAmount(pwallet->chain(), request.params[1], "");
msg.withdraw = true;

if (!request.params[2].isNull()) {
msg.destination = request.params[2].get_int();
}

// Encode
CDataStream metadata(DfTxMarker, SER_NETWORK, PROTOCOL_VERSION);
metadata << static_cast<unsigned char>(CustomTxType::DFIP2203)
<< msg;

CScript scriptMeta;
scriptMeta << OP_RETURN << ToByteVector(metadata);

int targetHeight = chainHeight(*pwallet->chain().lock()) + 1;

const auto txVersion = GetTransactionVersion(targetHeight);
CMutableTransaction rawTx(txVersion);

rawTx.vout.emplace_back(0, scriptMeta);

CTransactionRef optAuthTx;
std::set<CScript> auth{msg.owner};
rawTx.vin = GetAuthInputsSmart(pwallet, rawTx.nVersion, auth, false, optAuthTx, request.params[3]);

// Set change address
CCoinControl coinControl;
coinControl.destChange = dest;

// Fund
fund(rawTx, pwallet, optAuthTx, &coinControl);

// Check execution
execTestTx(CTransaction(rawTx), targetHeight, optAuthTx);

return signsend(rawTx, pwallet, optAuthTx)->GetHash().GetHex();
}

UniValue listpendingfutures(const JSONRPCRequest& request) {
RPCHelpMan{"listpendingfutures",
"Get all pending futures.\n",
Expand Down Expand Up @@ -2142,7 +2226,7 @@ UniValue listpendingfutures(const JSONRPCRequest& request) {

UniValue listFutures{UniValue::VARR};
pcustomcsview->ForEachFuturesUserValues([&](const CFuturesUserKey& key, const CFuturesUserValue& futuresValues){
if (key.height < startPeriod) {
if (key.height <= startPeriod) {
return false;
}

Expand Down Expand Up @@ -2214,7 +2298,7 @@ UniValue getpendingfutures(const JSONRPCRequest& request) {

std::vector<CFuturesUserValue> storedFutures;
pcustomcsview->ForEachFuturesUserValues([&](const CFuturesUserKey& key, const CFuturesUserValue& futuresValues) {
if (key.height < startPeriod) {
if (key.height <= startPeriod) {
return false;
}

Expand Down Expand Up @@ -2277,6 +2361,7 @@ static const CRPCCommand commands[] =
{"accounts", "getburninfo", &getburninfo, {}},
{"accounts", "executesmartcontract", &executesmartcontract, {"name", "amount", "inputs"}},
{"accounts", "futureswap", &futureswap, {"name", "amount", "destination", "inputs"}},
{"accounts", "withdrawfutureswap", &withdrawfutureswap, {"name", "amount", "destination", "inputs"}},
{"accounts", "listpendingfutures", &listpendingfutures, {}},
{"accounts", "getpendingfutures", &getpendingfutures, {"address"}},
};
Expand Down
2 changes: 2 additions & 0 deletions src/rpc/client.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,8 @@ static const CRPCConvertParam vRPCConvertParams[] =
{ "accounttoutxos", 2, "inputs" },
{ "futureswap", 2, "destination"},
{ "futureswap", 3, "inputs"},
{ "withdrawfutureswap", 2, "destination"},
{ "withdrawfutureswap", 3, "inputs"},

{ "icx_createorder", 0, "order" },
{ "icx_createorder", 1, "inputs" },
Expand Down
6 changes: 4 additions & 2 deletions src/validation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3337,8 +3337,10 @@ void CChainState::ProcessFutures(const CBlockIndex* pindex, CCustomCSView& cache
assert(destToken);

const auto& premiumPrice = futuresPrices.at(destId).premium;
const auto total = DivideAmounts(futuresValues.source.nValue, premiumPrice);
cache.AddBalance(key.owner, {destId, total});
if (premiumPrice > 0) {
const auto total = DivideAmounts(futuresValues.source.nValue, premiumPrice);
cache.AddBalance(key.owner, {destId, total});
}
} else {
const auto tokenDUSD = cache.GetToken("DUSD");
assert(tokenDUSD);
Expand Down
Loading

0 comments on commit 2a137e5

Please sign in to comment.