mirror of
https://github.com/Xahau/xahaud.git
synced 2026-01-21 15:15:15 +00:00
Compare commits
27 Commits
options-re
...
feature-se
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4d130bd9f7 | ||
|
|
9d4ee7cff5 | ||
|
|
51541cd95a | ||
|
|
b9628271a4 | ||
|
|
90405f728c | ||
|
|
2220f65cb2 | ||
|
|
77f9415e51 | ||
|
|
fa7406fe1e | ||
|
|
84eee588d3 | ||
|
|
849a4435e0 | ||
|
|
247e9d98bf | ||
|
|
03569dbb11 | ||
|
|
cb77121e20 | ||
|
|
c55a97c51a | ||
|
|
fc0be9c416 | ||
|
|
aaccf9b5b2 | ||
|
|
17af075665 | ||
|
|
e6b362c832 | ||
|
|
5b2b915955 | ||
|
|
e801ead39d | ||
|
|
78a96dd633 | ||
|
|
b3984c166d | ||
|
|
945f737706 | ||
|
|
8360ff8bc2 | ||
|
|
c1274d2a12 | ||
|
|
4aa79b6100 | ||
|
|
6a4c563ced |
22
.github/workflows/build-in-docker.yml
vendored
22
.github/workflows/build-in-docker.yml
vendored
@@ -2,25 +2,37 @@ name: Build using Docker
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ "dev", "candidate", "release" ]
|
||||
branches: [ "dev", "candidate", "release", "jshooks" ]
|
||||
pull_request:
|
||||
branches: [ "dev", "candidate", "release" ]
|
||||
branches: [ "dev", "candidate", "release", "jshooks" ]
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
group: ${{ github.workflow }}
|
||||
cancel-in-progress: false
|
||||
|
||||
jobs:
|
||||
builder:
|
||||
checkout:
|
||||
runs-on: [self-hosted, vanity]
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
clean: false
|
||||
checkpatterns:
|
||||
runs-on: [self-hosted, vanity]
|
||||
needs: checkout
|
||||
steps:
|
||||
- name: Check for suspicious patterns
|
||||
run: /bin/bash suspicious_patterns.sh
|
||||
build:
|
||||
runs-on: [self-hosted, vanity]
|
||||
needs: checkpatterns
|
||||
steps:
|
||||
- name: Build using Docker
|
||||
run: /bin/bash release-builder.sh
|
||||
tests:
|
||||
runs-on: [self-hosted, vanity]
|
||||
needs: build
|
||||
steps:
|
||||
- name: Unit tests
|
||||
run: /bin/bash docker-unit-tests.sh
|
||||
|
||||
|
||||
@@ -88,7 +88,6 @@ target_sources (xrpl_core PRIVATE
|
||||
src/ripple/protocol/impl/Issue.cpp
|
||||
src/ripple/protocol/impl/Keylet.cpp
|
||||
src/ripple/protocol/impl/LedgerFormats.cpp
|
||||
src/ripple/protocol/impl/Option.cpp
|
||||
src/ripple/protocol/impl/PublicKey.cpp
|
||||
src/ripple/protocol/impl/Quality.cpp
|
||||
src/ripple/protocol/impl/Rate2.cpp
|
||||
@@ -220,7 +219,6 @@ install (
|
||||
src/ripple/protocol/Keylet.h
|
||||
src/ripple/protocol/KnownFormats.h
|
||||
src/ripple/protocol/LedgerFormats.h
|
||||
src/ripple/protocol/Option.h
|
||||
src/ripple/protocol/Protocol.h
|
||||
src/ripple/protocol/PublicKey.h
|
||||
src/ripple/protocol/Quality.h
|
||||
@@ -435,32 +433,30 @@ target_sources (rippled PRIVATE
|
||||
src/ripple/app/tx/impl/CancelOffer.cpp
|
||||
src/ripple/app/tx/impl/CashCheck.cpp
|
||||
src/ripple/app/tx/impl/Change.cpp
|
||||
src/ripple/app/tx/impl/ClaimReward.cpp
|
||||
src/ripple/app/tx/impl/CreateCheck.cpp
|
||||
src/ripple/app/tx/impl/CreateOffer.cpp
|
||||
src/ripple/app/tx/impl/CreateTicket.cpp
|
||||
src/ripple/app/tx/impl/DeleteAccount.cpp
|
||||
src/ripple/app/tx/impl/DepositPreauth.cpp
|
||||
src/ripple/app/tx/impl/Escrow.cpp
|
||||
src/ripple/app/tx/impl/GenesisMint.cpp
|
||||
src/ripple/app/tx/impl/Import.cpp
|
||||
src/ripple/app/tx/impl/InvariantCheck.cpp
|
||||
src/ripple/app/tx/impl/Invoke.cpp
|
||||
src/ripple/app/tx/impl/NFTokenAcceptOffer.cpp
|
||||
src/ripple/app/tx/impl/NFTokenBurn.cpp
|
||||
src/ripple/app/tx/impl/NFTokenCancelOffer.cpp
|
||||
src/ripple/app/tx/impl/NFTokenCreateOffer.cpp
|
||||
src/ripple/app/tx/impl/NFTokenMint.cpp
|
||||
src/ripple/app/tx/impl/OfferStream.cpp
|
||||
src/ripple/app/tx/impl/OptionCreate.cpp
|
||||
src/ripple/app/tx/impl/OptionExercise.cpp
|
||||
src/ripple/app/tx/impl/OptionList.cpp
|
||||
src/ripple/app/tx/impl/PayChan.cpp
|
||||
src/ripple/app/tx/impl/Payment.cpp
|
||||
src/ripple/app/tx/impl/SetAccount.cpp
|
||||
src/ripple/app/tx/impl/SetRegularKey.cpp
|
||||
src/ripple/app/tx/impl/SetHook.cpp
|
||||
src/ripple/app/tx/impl/ClaimReward.cpp
|
||||
src/ripple/app/tx/impl/GenesisMint.cpp
|
||||
src/ripple/app/tx/impl/Import.cpp
|
||||
src/ripple/app/tx/impl/Invoke.cpp
|
||||
src/ripple/app/tx/impl/Remit.cpp
|
||||
src/ripple/app/tx/impl/SetAccount.cpp
|
||||
src/ripple/app/tx/impl/SetHook.cpp
|
||||
src/ripple/app/tx/impl/SetHookDefinition.cpp
|
||||
src/ripple/app/tx/impl/SetRegularKey.cpp
|
||||
src/ripple/app/tx/impl/SetSignerList.cpp
|
||||
src/ripple/app/tx/impl/SetTrust.cpp
|
||||
src/ripple/app/tx/impl/SignerEntries.cpp
|
||||
@@ -634,7 +630,6 @@ target_sources (rippled PRIVATE
|
||||
src/ripple/rpc/handlers/NFTOffers.cpp
|
||||
src/ripple/rpc/handlers/NodeToShard.cpp
|
||||
src/ripple/rpc/handlers/NoRippleCheck.cpp
|
||||
src/ripple/rpc/handlers/OptionBookOffers.cpp
|
||||
src/ripple/rpc/handlers/OwnerInfo.cpp
|
||||
src/ripple/rpc/handlers/PathFind.cpp
|
||||
src/ripple/rpc/handlers/PayChanClaim.cpp
|
||||
@@ -738,7 +733,6 @@ if (tests)
|
||||
src/test/app/NFTokenBurn_test.cpp
|
||||
src/test/app/NFTokenDir_test.cpp
|
||||
src/test/app/OfferStream_test.cpp
|
||||
src/test/app/Option_test.cpp
|
||||
src/test/app/Offer_test.cpp
|
||||
src/test/app/OversizeMeta_test.cpp
|
||||
src/test/app/Path_test.cpp
|
||||
@@ -764,6 +758,7 @@ if (tests)
|
||||
src/test/app/ValidatorList_test.cpp
|
||||
src/test/app/ValidatorSite_test.cpp
|
||||
src/test/app/SetHook_test.cpp
|
||||
src/test/app/SetHookDefinition_test.cpp
|
||||
src/test/app/SetHookTSH_test.cpp
|
||||
src/test/app/Wildcard_test.cpp
|
||||
src/test/app/XahauGenesis_test.cpp
|
||||
|
||||
@@ -53,7 +53,7 @@ Loop: test.app test.jtx
|
||||
test.app > test.jtx
|
||||
|
||||
Loop: test.app test.rpc
|
||||
test.rpc == test.app
|
||||
test.rpc ~= test.app
|
||||
|
||||
Loop: test.jtx test.toplevel
|
||||
test.toplevel > test.jtx
|
||||
|
||||
@@ -19,6 +19,7 @@ enum HookSetFlags : uint8_t {
|
||||
hsfOVERRIDE = 0b00000001U, // override or delete hook
|
||||
hsfNSDELETE = 0b00000010U, // delete namespace
|
||||
hsfCOLLECT = 0b00000100U, // allow collect calls on this hook
|
||||
hsfMUTALBE = 0b00001000U, // allow mutable hook definition
|
||||
};
|
||||
|
||||
enum HookEmissionFlags : uint16_t {
|
||||
|
||||
@@ -85,11 +85,9 @@ OrderBookDB::update(std::shared_ptr<ReadView const> const& ledger)
|
||||
return;
|
||||
}
|
||||
|
||||
decltype(optionBooks_) optionBooks;
|
||||
decltype(allBooks_) allBooks;
|
||||
decltype(xrpBooks_) xrpBooks;
|
||||
|
||||
optionBooks.reserve(optionBooks_.size());
|
||||
allBooks.reserve(allBooks_.size());
|
||||
xrpBooks.reserve(xrpBooks_.size());
|
||||
|
||||
@@ -163,14 +161,6 @@ OrderBookDB::addOrderBook(Book const& book)
|
||||
xrpBooks_.insert(book.in);
|
||||
}
|
||||
|
||||
void
|
||||
OrderBookDB::addOptionOrderBook(Option const& option)
|
||||
{
|
||||
std::lock_guard sl(mLock);
|
||||
|
||||
optionBooks_.insert(option.issue);
|
||||
}
|
||||
|
||||
// return list of all orderbooks that want this issuerID and currencyID
|
||||
std::vector<Book>
|
||||
OrderBookDB::getBooksByTakerPays(Issue const& issue)
|
||||
|
||||
@@ -23,7 +23,6 @@
|
||||
#include <ripple/app/ledger/AcceptedLedgerTx.h>
|
||||
#include <ripple/app/ledger/BookListeners.h>
|
||||
#include <ripple/app/main/Application.h>
|
||||
#include <ripple/protocol/Option.h>
|
||||
#include <mutex>
|
||||
|
||||
namespace ripple {
|
||||
@@ -41,9 +40,6 @@ public:
|
||||
void
|
||||
addOrderBook(Book const&);
|
||||
|
||||
void
|
||||
addOptionOrderBook(Option const&);
|
||||
|
||||
/** @return a list of all orderbooks that want this issuerID and currencyID.
|
||||
*/
|
||||
std::vector<Book>
|
||||
@@ -59,7 +55,6 @@ public:
|
||||
|
||||
BookListeners::pointer
|
||||
getBookListeners(Book const&);
|
||||
|
||||
BookListeners::pointer
|
||||
makeBookListeners(Book const&);
|
||||
|
||||
@@ -76,9 +71,6 @@ private:
|
||||
// Maps order books by "issue in" to "issue out":
|
||||
hardened_hash_map<Issue, hardened_hash_set<Issue>> allBooks_;
|
||||
|
||||
// does an order book to XRP exist
|
||||
hash_set<Issue> optionBooks_;
|
||||
|
||||
// does an order book to XRP exist
|
||||
hash_set<Issue> xrpBooks_;
|
||||
|
||||
|
||||
@@ -19,7 +19,9 @@
|
||||
|
||||
#include <ripple/app/consensus/RCLValidations.h>
|
||||
#include <ripple/app/ledger/Ledger.h>
|
||||
#include <ripple/app/main/Application.h>
|
||||
#include <ripple/app/misc/NegativeUNLVote.h>
|
||||
#include <ripple/json/to_string.h>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
|
||||
@@ -350,15 +350,6 @@ public:
|
||||
unsigned int iLimit,
|
||||
Json::Value const& jvMarker,
|
||||
Json::Value& jvResult) override;
|
||||
|
||||
void
|
||||
getOptionBookPage(
|
||||
std::shared_ptr<ReadView const>& lpLedger,
|
||||
STAmount const&,
|
||||
std::uint32_t const& expiration,
|
||||
unsigned int iLimit,
|
||||
Json::Value const& jvMarker,
|
||||
Json::Value& jvResult) override;
|
||||
|
||||
// Ledger proposal/close functions.
|
||||
bool
|
||||
@@ -4590,114 +4581,6 @@ NetworkOPsImp::getBookPage(
|
||||
|
||||
#endif
|
||||
|
||||
void
|
||||
NetworkOPsImp::getOptionBookPage(
|
||||
std::shared_ptr<ReadView const>& lpLedger,
|
||||
STAmount const& strikePrice,
|
||||
std::uint32_t const& expiration,
|
||||
unsigned int iLimit,
|
||||
Json::Value const& jvMarker,
|
||||
Json::Value& jvResult)
|
||||
{
|
||||
Json::Value& jvOffers = (jvResult[jss::offers] = Json::Value(Json::arrayValue));
|
||||
|
||||
const uint256 uBookBase = getOptionBookBase(
|
||||
strikePrice.getIssuer(),
|
||||
strikePrice.getCurrency(),
|
||||
strikePrice.mantissa(),
|
||||
expiration);
|
||||
const uint256 uBookEnd = getOptionQualityNext(uBookBase);
|
||||
|
||||
uint256 uTipIndex = uBookBase;
|
||||
|
||||
if (auto stream = m_journal.trace())
|
||||
{
|
||||
stream << "getBookPage:" << strikePrice;
|
||||
stream << "getBookPage: uBookBase=" << uBookBase;
|
||||
stream << "getBookPage: uBookEnd=" << uBookEnd;
|
||||
stream << "getBookPage: uTipIndex=" << uTipIndex;
|
||||
}
|
||||
|
||||
ReadView const& view = *lpLedger;
|
||||
|
||||
bool bDone = false;
|
||||
bool bDirectAdvance = true;
|
||||
|
||||
std::shared_ptr<SLE const> sleOfferDir;
|
||||
uint256 offerIndex;
|
||||
unsigned int uBookEntry;
|
||||
STAmount saDirRate;
|
||||
|
||||
auto viewJ = app_.journal("View");
|
||||
|
||||
while (!bDone && iLimit-- > 0)
|
||||
{
|
||||
if (bDirectAdvance)
|
||||
{
|
||||
bDirectAdvance = false;
|
||||
|
||||
JLOG(m_journal.trace()) << "getBookPage: bDirectAdvance";
|
||||
|
||||
auto const ledgerIndex = view.succ(uTipIndex, uBookEnd);
|
||||
if (ledgerIndex)
|
||||
{
|
||||
sleOfferDir = view.read(keylet::page(*ledgerIndex));
|
||||
}
|
||||
else
|
||||
{
|
||||
sleOfferDir.reset();
|
||||
}
|
||||
|
||||
if (!sleOfferDir)
|
||||
{
|
||||
JLOG(m_journal.trace()) << "getBookPage: bDone";
|
||||
bDone = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
uTipIndex = sleOfferDir->key();
|
||||
cdirFirst(view, uTipIndex, sleOfferDir, uBookEntry, offerIndex);
|
||||
|
||||
JLOG(m_journal.trace())
|
||||
<< "getBookPage: uTipIndex=" << uTipIndex;
|
||||
JLOG(m_journal.trace())
|
||||
<< "getBookPage: offerIndex=" << offerIndex;
|
||||
}
|
||||
}
|
||||
|
||||
if (!bDone)
|
||||
{
|
||||
auto sleOffer = view.read(keylet::optionOffer(offerIndex));
|
||||
|
||||
if (sleOffer)
|
||||
{
|
||||
STAmount premium = sleOffer->getFieldAmount(sfAmount);
|
||||
auto const optionQuality = getOptionQuality(uTipIndex);
|
||||
STAmount saDirRate = STAmount(premium.issue(), optionQuality);
|
||||
|
||||
Json::Value jvOffer = sleOffer->getJson(JsonOptions::none);
|
||||
|
||||
Json::Value& jvOf = jvOffers.append(jvOffer);
|
||||
jvOf[jss::quality] = saDirRate.getText();
|
||||
}
|
||||
else
|
||||
{
|
||||
JLOG(m_journal.warn()) << "Missing offer";
|
||||
}
|
||||
|
||||
if (!cdirNext(view, uTipIndex, sleOfferDir, uBookEntry, offerIndex))
|
||||
{
|
||||
bDirectAdvance = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
JLOG(m_journal.trace())
|
||||
<< "getBookPage: offerIndex=" << offerIndex;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline void
|
||||
NetworkOPsImp::collect_metrics()
|
||||
{
|
||||
|
||||
@@ -163,15 +163,6 @@ public:
|
||||
unsigned int iLimit,
|
||||
Json::Value const& jvMarker,
|
||||
Json::Value& jvResult) = 0;
|
||||
|
||||
virtual void
|
||||
getOptionBookPage(
|
||||
std::shared_ptr<ReadView const>& lpLedger,
|
||||
STAmount const& strikePrice,
|
||||
std::uint32_t const& expiration,
|
||||
unsigned int iLimit,
|
||||
Json::Value const& jvMarker,
|
||||
Json::Value& jvResult) = 0;
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include <ripple/ledger/View.h>
|
||||
#include <ripple/protocol/Feature.h>
|
||||
#include <ripple/protocol/Indexes.h>
|
||||
#include <ripple/protocol/st.h>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
|
||||
@@ -24,12 +24,15 @@
|
||||
#include <ripple/basics/base64.h>
|
||||
#include <ripple/json/json_reader.h>
|
||||
#include <ripple/json/json_value.h>
|
||||
#include <ripple/json/to_string.h>
|
||||
#include <ripple/ledger/View.h>
|
||||
#include <ripple/protocol/Feature.h>
|
||||
#include <ripple/protocol/Import.h>
|
||||
#include <ripple/protocol/Indexes.h>
|
||||
#include <ripple/protocol/PublicKey.h>
|
||||
#include <ripple/protocol/STTx.h>
|
||||
#include <ripple/protocol/STValidation.h>
|
||||
#include <ripple/protocol/st.h>
|
||||
#include <algorithm>
|
||||
#include <charconv>
|
||||
#include <iostream>
|
||||
|
||||
@@ -109,10 +109,6 @@ XRPNotCreated::visitEntry(
|
||||
if (isXRP((*before)[sfAmount]))
|
||||
drops_ -= (*before)[sfAmount].xrp().drops();
|
||||
break;
|
||||
case ltOPTION_OFFER:
|
||||
if (isXRP((*before)[sfLockedBalance]))
|
||||
drops_ -= (*before)[sfLockedBalance].xrp().drops();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -135,10 +131,6 @@ XRPNotCreated::visitEntry(
|
||||
if (!isDelete && isXRP((*after)[sfAmount]))
|
||||
drops_ += (*after)[sfAmount].xrp().drops();
|
||||
break;
|
||||
case ltOPTION_OFFER:
|
||||
if (!isDelete && isXRP((*after)[sfLockedBalance]))
|
||||
drops_ += (*after)[sfLockedBalance].xrp().drops();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -500,8 +492,6 @@ LedgerEntryTypesMatch::visitEntry(
|
||||
case ltURI_TOKEN:
|
||||
case ltIMPORT_VLSEQ:
|
||||
case ltUNL_REPORT:
|
||||
case ltOPTION:
|
||||
case ltOPTION_OFFER:
|
||||
break;
|
||||
default:
|
||||
invalidTypeAdded_ = true;
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include <ripple/ledger/View.h>
|
||||
#include <ripple/protocol/Feature.h>
|
||||
#include <ripple/protocol/Indexes.h>
|
||||
#include <ripple/protocol/st.h>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
|
||||
@@ -1,473 +0,0 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2024 XRPL-Labs
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#include <ripple/app/ledger/OrderBookDB.h>
|
||||
#include <ripple/app/tx/impl/OptionCreate.h>
|
||||
#include <ripple/basics/Log.h>
|
||||
#include <ripple/ledger/ApplyView.h>
|
||||
#include <ripple/ledger/View.h>
|
||||
#include <ripple/protocol/Feature.h>
|
||||
#include <ripple/protocol/Indexes.h>
|
||||
#include <ripple/protocol/Option.h>
|
||||
#include <ripple/protocol/STAccount.h>
|
||||
#include <ripple/protocol/TxFlags.h>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
TxConsequences
|
||||
OptionCreate::makeTxConsequences(PreflightContext const& ctx)
|
||||
{
|
||||
return TxConsequences{ctx.tx, TxConsequences::normal};
|
||||
}
|
||||
|
||||
NotTEC
|
||||
OptionCreate::preflight(PreflightContext const& ctx)
|
||||
{
|
||||
if (auto const ret = preflight1(ctx); !isTesSuccess(ret))
|
||||
return ret;
|
||||
|
||||
if (ctx.tx.getFlags() & tfOptionCreateMask)
|
||||
{
|
||||
JLOG(ctx.j.warn()) << "OptionCreate: Invalid flags set.";
|
||||
return temINVALID_FLAG;
|
||||
}
|
||||
|
||||
auto const flags = ctx.tx.getFlags();
|
||||
std::optional<uint256> const swapID = ctx.tx[~sfSwapID];
|
||||
std::uint32_t const quantity = ctx.tx.getFieldU32(sfQuantity);
|
||||
|
||||
bool const isClose = (flags & tfPosition) != 0;
|
||||
|
||||
if (isClose && !swapID)
|
||||
{
|
||||
JLOG(ctx.j.warn())
|
||||
<< "OptionCreate: Cannot close option without swap ID.";
|
||||
return temMALFORMED;
|
||||
}
|
||||
|
||||
if (quantity % 100)
|
||||
{
|
||||
JLOG(ctx.j.warn())
|
||||
<< "OptionCreate: Quantity must be a multple of 100.";
|
||||
return temMALFORMED;
|
||||
}
|
||||
}
|
||||
|
||||
std::optional<uint256>
|
||||
sealOption(
|
||||
Sandbox& sb,
|
||||
STAmount strikePrice,
|
||||
std::uint32_t expiration,
|
||||
bool isPut,
|
||||
bool isSell)
|
||||
{
|
||||
const uint256 uBookBaseOpp = getOptionBookBase(
|
||||
strikePrice.getIssuer(),
|
||||
strikePrice.getCurrency(),
|
||||
strikePrice.mantissa(),
|
||||
expiration);
|
||||
// std::cout << "BOOK BASE: " << uBookBaseOpp << "\n";
|
||||
const uint256 uBookEndOpp = getOptionQualityNext(uBookBaseOpp);
|
||||
// std::cout << "BOOK BASE END: " << uBookEndOpp << "\n";
|
||||
auto key = sb.succ(uBookBaseOpp, uBookEndOpp);
|
||||
if (!key)
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
auto sleOfferDir = sb.read(keylet::page(key.value()));
|
||||
uint256 offerIndex;
|
||||
unsigned int bookEntry;
|
||||
|
||||
if (!cdirFirst(sb, sleOfferDir->key(), sleOfferDir, bookEntry, offerIndex))
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
// auto sleOffer = sb.read(keylet::unchecked(offerIndex));
|
||||
// STAmount premium = sleOffer->getFieldAmount(sfAmount);
|
||||
// auto const dir = to_string(sleOffer->getFieldH256(sfBookDirectory));
|
||||
// std::cout << "dir: " << dir << "\n";
|
||||
// auto const uTipIndex = sleOfferDir->key();
|
||||
// auto const optionQuality = getOptionQuality(uTipIndex);
|
||||
// std::cout << "optionQuality: " << optionQuality << "\n";
|
||||
// STAmount dirRate = STAmount(premium.issue(), optionQuality);
|
||||
// std::cout << "dirRate: " << dirRate << "\n";
|
||||
// BEAST_EXPECT(100 / rate == 110);
|
||||
|
||||
do
|
||||
{
|
||||
auto sleItem = sb.read(keylet::child(offerIndex));
|
||||
if (!sleItem)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
auto const flags = sleItem->getFlags();
|
||||
bool const _isPut = (flags & tfType) != 0;
|
||||
bool const _isSell = (flags & tfAction) != 0;
|
||||
|
||||
// Skip Sealed Options
|
||||
if (sleItem->getFieldU32(sfOpenInterest) == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// looking for oposite option position.
|
||||
if (_isPut == isPut && _isSell != isSell)
|
||||
{
|
||||
uint256 const sealID = sleItem->getFieldH256(sfSwapID);
|
||||
if (sealID.isNonZero())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
return offerIndex;
|
||||
}
|
||||
}
|
||||
} while (
|
||||
cdirNext(sb, sleOfferDir->key(), sleOfferDir, bookEntry, offerIndex));
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
TER
|
||||
OptionCreate::doApply()
|
||||
{
|
||||
if (!view().rules().enabled(featureOptions))
|
||||
return temDISABLED;
|
||||
|
||||
Sandbox sb(&ctx_.view());
|
||||
|
||||
beast::Journal const& j = ctx_.journal;
|
||||
|
||||
AccountID const srcAccID = ctx_.tx.getAccountID(sfAccount);
|
||||
uint256 const optionID = ctx_.tx.getFieldH256(sfOptionID);
|
||||
auto const flags = ctx_.tx.getFlags();
|
||||
STAmount const premium = ctx_.tx.getFieldAmount(sfAmount);
|
||||
std::uint32_t const quantity = ctx_.tx.getFieldU32(sfQuantity);
|
||||
std::optional<uint256> const swapID = ctx_.tx[~sfSwapID];
|
||||
|
||||
STAmount const totalPremium = mulRound(premium, STAmount(premium.issue(), quantity), premium.issue(), false);
|
||||
|
||||
auto sleSrcAcc = sb.peek(keylet::account(srcAccID));
|
||||
if (!sleSrcAcc)
|
||||
return terNO_ACCOUNT;
|
||||
|
||||
auto sleOptionAcc = sb.peek(keylet::unchecked(optionID));
|
||||
if (!sleOptionAcc)
|
||||
return tecINTERNAL;
|
||||
|
||||
STAmount const strikePrice = sleOptionAcc->getFieldAmount(sfStrikePrice);
|
||||
std::uint32_t const expiration = sleOptionAcc->getFieldU32(sfExpiration);
|
||||
AccountID const issuer = sleOptionAcc->getAccountID(sfIssuer);
|
||||
Currency const currency = Currency(sleOptionAcc->getFieldH160(sfCurrency));
|
||||
// STAmount const quantityShares = STAmount({ issuer, currency }, isXRP(strikePrice) ? quantity * 1000000 : quantity);
|
||||
STAmount const quantityShares = STAmount(Issue(currency, issuer), quantity);
|
||||
|
||||
if (strikePrice.issue() != totalPremium.issue() || strikePrice.issue() != totalPremium.issue())
|
||||
return temBAD_ISSUER;
|
||||
|
||||
bool const isPut = (flags & tfType) != 0;
|
||||
bool const isSell = (flags & tfAction) != 0;
|
||||
bool const isClose = (flags & tfPosition) != 0;
|
||||
|
||||
std::cout << "OptionCreate.getIssuer(): " << strikePrice.getIssuer() << "\n";
|
||||
std::cout << "OptionCreate.getCurrency(): " << strikePrice.getCurrency() << "\n";
|
||||
std::cout << "OptionCreate.mantissa(): " << strikePrice.mantissa() << "\n";
|
||||
std::cout << "OptionCreate.exponent(): " << strikePrice.exponent() << "\n";
|
||||
std::cout << "OptionCreate.value(): " << strikePrice.value() << "\n";
|
||||
std::cout << "OptionCreate.expiration: " << expiration << "\n";
|
||||
|
||||
auto optionBookDirKeylet = keylet::optionBook(
|
||||
strikePrice.getIssuer(),
|
||||
strikePrice.getCurrency(),
|
||||
strikePrice.mantissa(),
|
||||
expiration);
|
||||
auto optionOfferKeylet =
|
||||
ripple::keylet::optionOffer(srcAccID, ctx_.tx.getSeqProxy().value());
|
||||
|
||||
std::optional<uint256> const sealID =
|
||||
sealOption(sb, strikePrice, expiration, isPut, isSell);
|
||||
|
||||
// Update Sealed Option
|
||||
AccountID oppAccID{AccountID{}};
|
||||
if (sealID)
|
||||
{
|
||||
JLOG(j.warn()) << "Updating Sealed Offer: sealID";
|
||||
auto sealedKeylet = ripple::keylet::unchecked(*sealID);
|
||||
auto sealedOption = sb.peek(sealedKeylet);
|
||||
sealedOption->setFieldH256(sfSwapID, optionOfferKeylet.key);
|
||||
uint32_t currSealed = sealedOption->getFieldU32(sfOpenInterest);
|
||||
sealedOption->setFieldU32(sfOpenInterest, currSealed - quantity);
|
||||
oppAccID = sealedOption->getAccountID(sfOwner);
|
||||
sb.update(sealedOption);
|
||||
}
|
||||
|
||||
// Block No Market Buys
|
||||
if (!isSell && !sealID)
|
||||
{
|
||||
JLOG(j.warn()) << "OptionCreate: No open sell offers exist.";
|
||||
return tecNO_TARGET;
|
||||
}
|
||||
|
||||
// Insert New Option (3 Times [issuer, party, counter-party])
|
||||
if (!isClose)
|
||||
{
|
||||
JLOG(j.warn()) << "Creating Option Offer: !isClose";
|
||||
// Add Option to Issuer
|
||||
// if (!isXRP(premium))
|
||||
// {
|
||||
// // unimplemented
|
||||
// return tecINTERNAL;
|
||||
// }
|
||||
|
||||
// Add Option to Self
|
||||
std::uint32_t ownerCount{(*sleSrcAcc)[sfOwnerCount]};
|
||||
++ownerCount;
|
||||
XRPAmount const newReserve{sb.fees().accountReserve(ownerCount)};
|
||||
adjustOwnerCount(sb, sleSrcAcc, 1, j);
|
||||
|
||||
auto optionOffer = std::make_shared<SLE>(optionOfferKeylet);
|
||||
auto const page = sb.dirInsert(
|
||||
keylet::ownerDir(account_),
|
||||
optionOfferKeylet,
|
||||
describeOwnerDir(account_));
|
||||
if (!page)
|
||||
{
|
||||
std::cout << "NO PAGE"
|
||||
<< "\n";
|
||||
return tecDIR_FULL;
|
||||
}
|
||||
|
||||
optionOffer->setFlag(flags);
|
||||
optionOffer->setAccountID(sfOwner, srcAccID);
|
||||
optionOffer->setFieldU64(sfOwnerNode, *page);
|
||||
optionOffer->setFieldH256(sfOptionID, optionID);
|
||||
optionOffer->setFieldU32(sfQuantity, quantity);
|
||||
optionOffer->setFieldU32(sfOpenInterest, quantity);
|
||||
optionOffer->setFieldAmount(sfAmount, premium); // Premium
|
||||
optionOffer->setFieldAmount(sfLockedBalance, STAmount(0)); // Locked
|
||||
if (sealID)
|
||||
{
|
||||
JLOG(j.warn()) << "Updating Option Offer: sealID";
|
||||
optionOffer->setFieldH256(sfSwapID, *sealID);
|
||||
optionOffer->setFieldU32(sfOpenInterest, 0);
|
||||
}
|
||||
if (isSell)
|
||||
{
|
||||
JLOG(j.warn()) << "Updating Option Offer: isSell";
|
||||
// Update the locked balance
|
||||
optionOffer->setFieldAmount(sfLockedBalance, quantityShares); // Locked
|
||||
}
|
||||
|
||||
Option const option{
|
||||
strikePrice.issue(), strikePrice.mantissa(), expiration};
|
||||
|
||||
// std::cout << "BOOK BASE: " << strikePrice.mantissa() << "\n";
|
||||
// std::cout << "PREMIUM: " << premium.mantissa() << "\n";
|
||||
|
||||
auto dir =
|
||||
keylet::optionQuality(optionBookDirKeylet, premium.mantissa());
|
||||
bool const bookExisted = static_cast<bool>(sb.peek(dir));
|
||||
auto const bookNode =
|
||||
sb.dirAppend(dir, optionOfferKeylet, [&](SLE::ref sle) {
|
||||
sle->setFieldH160(
|
||||
sfTakerPaysIssuer, strikePrice.issue().account);
|
||||
sle->setFieldH160(
|
||||
sfTakerPaysCurrency, strikePrice.issue().currency);
|
||||
sle->setFieldU64(sfBaseFee, strikePrice.mantissa());
|
||||
sle->setFieldU32(sfExpiration, expiration);
|
||||
sle->setFieldU64(sfExchangeRate, premium.mantissa());
|
||||
});
|
||||
|
||||
if (!bookNode)
|
||||
{
|
||||
JLOG(j_.debug()) << "final result: failed to add offer to book";
|
||||
return tecDIR_FULL;
|
||||
}
|
||||
|
||||
// if (!bookExisted)
|
||||
// ctx_.app.getOrderBookDB().addOptionOrderBook(option);
|
||||
|
||||
optionOffer->setFieldH256(sfBookDirectory, dir.key);
|
||||
optionOffer->setFieldU64(sfBookNode, *bookNode);
|
||||
sb.insert(optionOffer);
|
||||
}
|
||||
|
||||
if (isClose)
|
||||
{
|
||||
JLOG(j.warn()) << "Updating Option Offer: isClose";
|
||||
auto optionOffer = sb.peek(optionOfferKeylet);
|
||||
uint256 const sealID = optionOffer->getFieldH256(sfSwapID);
|
||||
if (!sealID)
|
||||
{
|
||||
JLOG(j.warn())
|
||||
<< "OptionCreate: Cannot close option that has not sealed.";
|
||||
return tecINTERNAL;
|
||||
}
|
||||
|
||||
// Update Swap Option
|
||||
auto swapKeylet = ripple::keylet::unchecked(*swapID);
|
||||
auto swapOption = sb.peek(swapKeylet);
|
||||
if (!swapOption)
|
||||
{
|
||||
JLOG(j.warn()) << "OptionCreate: Swap Option does not exist.";
|
||||
return tecINTERNAL;
|
||||
}
|
||||
swapOption->setFieldH256(sfSwapID, optionOfferKeylet.key);
|
||||
sb.update(swapOption);
|
||||
|
||||
// Update New Option
|
||||
optionOffer->setFieldH256(sfSwapID, *swapID);
|
||||
sb.update(optionOffer);
|
||||
|
||||
// Erase Swap Sealed Option
|
||||
uint256 const swapSealedID = swapOption->getFieldH256(sfSwapID);
|
||||
if (!swapSealedID)
|
||||
{
|
||||
JLOG(j.warn()) << "OptionCreate: Swap Option is not sealed.";
|
||||
return tecINTERNAL;
|
||||
}
|
||||
auto swapSealedKeylet = ripple::keylet::unchecked(swapSealedID);
|
||||
auto swapSealedOption = sb.peek(swapSealedKeylet);
|
||||
if (!swapSealedOption)
|
||||
{
|
||||
JLOG(j.warn())
|
||||
<< "OptionCreate: Swap Sealed Option does not exist.";
|
||||
return tecINTERNAL;
|
||||
}
|
||||
sb.erase(swapSealedOption);
|
||||
|
||||
// Erase New Sealed Option
|
||||
auto sealedKeylet = ripple::keylet::unchecked(sealID);
|
||||
auto sealedOption = sb.peek(sealedKeylet);
|
||||
sb.erase(sealedOption);
|
||||
}
|
||||
|
||||
// xfer the premium from the buyer to the seller
|
||||
if (!isSell && sealID)
|
||||
{
|
||||
JLOG(j.warn()) << "Updating Option Balances: !isSell && sealID";
|
||||
auto sleOppAcc = sb.peek(keylet::account(oppAccID));
|
||||
if (!sleOppAcc)
|
||||
return terNO_ACCOUNT;
|
||||
|
||||
// Native
|
||||
if (isXRP(premium))
|
||||
{
|
||||
// ensure the account can cover the native
|
||||
if (mSourceBalance < totalPremium.xrp())
|
||||
return tecUNFUNDED_PAYMENT;
|
||||
|
||||
// subtract the premium from the buyer
|
||||
{
|
||||
STAmount bal = mSourceBalance;
|
||||
bal -= totalPremium.xrp();
|
||||
if (bal < beast::zero || bal > mSourceBalance)
|
||||
return tecINTERNAL;
|
||||
sleSrcAcc->setFieldAmount(sfBalance, bal);
|
||||
}
|
||||
|
||||
// add the premium to the writer
|
||||
{
|
||||
STAmount bal = sleOppAcc->getFieldAmount(sfBalance);
|
||||
STAmount prior = bal;
|
||||
bal += totalPremium.xrp();
|
||||
if (bal < beast::zero || bal < prior)
|
||||
return tecINTERNAL;
|
||||
sleOppAcc->setFieldAmount(sfBalance, bal);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// // 1. & 2.
|
||||
TER canBuyerXfer = trustTransferAllowed(
|
||||
sb,
|
||||
std::vector<AccountID>{srcAccID, oppAccID},
|
||||
totalPremium.issue(),
|
||||
j);
|
||||
|
||||
if (!isTesSuccess(canBuyerXfer))
|
||||
{
|
||||
return canBuyerXfer;
|
||||
}
|
||||
|
||||
STAmount availableBuyerFunds{accountFunds(
|
||||
sb, srcAccID, totalPremium, fhZERO_IF_FROZEN, j)};
|
||||
|
||||
|
||||
JLOG(j.warn()) << "availableBuyerFunds: " << availableBuyerFunds << "/n";
|
||||
JLOG(j.warn()) << "totalPremium: " << totalPremium << "/n";
|
||||
if (availableBuyerFunds < totalPremium)
|
||||
return tecUNFUNDED_PAYMENT;
|
||||
|
||||
if (TER result = accountSend(sb, srcAccID, oppAccID, totalPremium, j, true); !isTesSuccess(result))
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
sb.update(sleOppAcc);
|
||||
}
|
||||
else
|
||||
{
|
||||
JLOG(j.warn()) << "Updating Option Balances: isSell";
|
||||
if (isXRP(quantityShares))
|
||||
{
|
||||
// subtract the quantity from the writer
|
||||
if (mSourceBalance < quantityShares.xrp())
|
||||
return tecUNFUNDED_PAYMENT;
|
||||
{
|
||||
STAmount bal = mSourceBalance;
|
||||
bal -= quantityShares.xrp();
|
||||
if (bal < beast::zero || bal > mSourceBalance)
|
||||
return tecINTERNAL;
|
||||
|
||||
sleSrcAcc->setFieldAmount(sfBalance, bal);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
STAmount availableBuyerFunds{accountFunds(
|
||||
sb, srcAccID, quantityShares, fhZERO_IF_FROZEN, j)};
|
||||
|
||||
if (availableBuyerFunds < quantityShares)
|
||||
return tecUNFUNDED_PAYMENT;
|
||||
|
||||
std::shared_ptr<SLE> sleLine = ctx_.view().peek(keylet::line(srcAccID, quantityShares.getIssuer(), quantityShares.getCurrency()));
|
||||
|
||||
if (TER const result = trustAdjustLockedBalance(ctx_.view(), sleLine, quantityShares, 1, ctx_.journal, WetRun); !isTesSuccess(result))
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
// apply
|
||||
sb.update(sleSrcAcc);
|
||||
sb.apply(ctx_.rawView());
|
||||
return tesSUCCESS;
|
||||
}
|
||||
|
||||
XRPAmount
|
||||
OptionCreate::calculateBaseFee(ReadView const& view, STTx const& tx)
|
||||
{
|
||||
return Transactor::calculateBaseFee(view, tx);
|
||||
}
|
||||
|
||||
} // namespace ripple
|
||||
@@ -1,54 +0,0 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2024 XRPL-Labs
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef RIPPLE_TX_OPTIONCREATE_H_INCLUDED
|
||||
#define RIPPLE_TX_OPTIONCREATE_H_INCLUDED
|
||||
|
||||
#include <ripple/app/tx/impl/Transactor.h>
|
||||
#include <ripple/basics/Log.h>
|
||||
#include <ripple/core/Config.h>
|
||||
#include <ripple/protocol/Indexes.h>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
class OptionCreate : public Transactor
|
||||
{
|
||||
public:
|
||||
static constexpr ConsequencesFactoryType ConsequencesFactory{Custom};
|
||||
|
||||
explicit OptionCreate(ApplyContext& ctx) : Transactor(ctx)
|
||||
{
|
||||
}
|
||||
|
||||
static XRPAmount
|
||||
calculateBaseFee(ReadView const& view, STTx const& tx);
|
||||
|
||||
static TxConsequences
|
||||
makeTxConsequences(PreflightContext const& ctx);
|
||||
|
||||
static NotTEC
|
||||
preflight(PreflightContext const& ctx);
|
||||
|
||||
TER
|
||||
doApply() override;
|
||||
};
|
||||
|
||||
} // namespace ripple
|
||||
|
||||
#endif
|
||||
@@ -1,258 +0,0 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2024 XRPL-Labs
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#include <ripple/app/tx/impl/OptionExercise.h>
|
||||
#include <ripple/basics/Log.h>
|
||||
#include <ripple/ledger/ApplyView.h>
|
||||
#include <ripple/ledger/View.h>
|
||||
#include <ripple/protocol/Feature.h>
|
||||
#include <ripple/protocol/Indexes.h>
|
||||
#include <ripple/protocol/STAccount.h>
|
||||
#include <ripple/protocol/TxFlags.h>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
TxConsequences
|
||||
OptionExercise::makeTxConsequences(PreflightContext const& ctx)
|
||||
{
|
||||
return TxConsequences{ctx.tx, TxConsequences::normal};
|
||||
}
|
||||
|
||||
NotTEC
|
||||
OptionExercise::preflight(PreflightContext const& ctx)
|
||||
{
|
||||
if (auto const ret = preflight1(ctx); !isTesSuccess(ret))
|
||||
return ret;
|
||||
|
||||
if (ctx.tx.getFlags() & tfOptionExpireMask)
|
||||
{
|
||||
// There are no flags (other than universal).
|
||||
JLOG(ctx.j.warn()) << "Malformed transaction: Invalid flags set.";
|
||||
return temINVALID_FLAG;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
TER
|
||||
OptionExercise::doApply()
|
||||
{
|
||||
if (!view().rules().enabled(featureOptions))
|
||||
return temDISABLED;
|
||||
|
||||
// Sandbox sb(&ctx_.view());
|
||||
|
||||
beast::Journal const& j = ctx_.journal;
|
||||
|
||||
AccountID const srcAccID = ctx_.tx.getAccountID(sfAccount);
|
||||
uint256 const optionID = ctx_.tx.getFieldH256(sfOptionID);
|
||||
uint256 const offerID = ctx_.tx.getFieldH256(sfSwapID);
|
||||
auto const flags = ctx_.tx.getFlags();
|
||||
|
||||
auto sleSrcAcc = ctx_.view().peek(keylet::account(srcAccID));
|
||||
if (!sleSrcAcc)
|
||||
return terNO_ACCOUNT;
|
||||
|
||||
auto optionOfferKeylet = ripple::keylet::unchecked(offerID);
|
||||
auto sleOptionOffer = ctx_.view().peek(optionOfferKeylet);
|
||||
if (!sleOptionOffer)
|
||||
return tecNO_TARGET;
|
||||
|
||||
AccountID const ownrAccID = sleOptionOffer->getAccountID(sfOwner);
|
||||
auto const sealedID = sleOptionOffer->getFieldH256(sfSwapID);
|
||||
auto oppOfferKeylet = ripple::keylet::unchecked(sealedID);
|
||||
auto sleSealedOffer = ctx_.view().peek(oppOfferKeylet);
|
||||
if (!sleSealedOffer)
|
||||
return tecNO_TARGET;
|
||||
|
||||
AccountID const oppAccID = sleSealedOffer->getAccountID(sfOwner);
|
||||
auto sleOppAcc = ctx_.view().peek(keylet::account(oppAccID));
|
||||
if (!sleOppAcc)
|
||||
return terNO_ACCOUNT;
|
||||
|
||||
auto const optionFlags = sleOptionOffer->getFlags();
|
||||
bool const isPut = (optionFlags & tfType) != 0;
|
||||
bool const isSell = (optionFlags & tfAction) != 0;
|
||||
|
||||
auto sleOption = ctx_.view().peek(keylet::unchecked(optionID));
|
||||
if (!sleOption)
|
||||
return tecINTERNAL;
|
||||
|
||||
STAmount const strikePrice = sleOption->getFieldAmount(sfStrikePrice);
|
||||
STAmount const quantityShares = sleSealedOffer->getFieldAmount(sfLockedBalance);
|
||||
std::uint32_t const quantity = sleOptionOffer->getFieldU32(sfQuantity);
|
||||
STAmount const totalValue = mulRound(strikePrice, STAmount(strikePrice.issue(), quantity), strikePrice.issue(), false);
|
||||
|
||||
|
||||
JLOG(j.warn()) << "OptionExercise: QUANTITY SHARES" << quantityShares << "\n";
|
||||
JLOG(j.warn()) << "OptionExercise: TOTAL VALUE" << totalValue << "\n";
|
||||
|
||||
if (flags & tfOptionExpire)
|
||||
{
|
||||
JLOG(j.warn()) << "OptionExercise: EXPIRE OPTION";
|
||||
ctx_.view().erase(sleSealedOffer);
|
||||
ctx_.view().erase(sleOptionOffer);
|
||||
// sb.apply(ctx_.rawView());
|
||||
return tesSUCCESS;
|
||||
}
|
||||
|
||||
switch (isPut)
|
||||
{
|
||||
case 0: {
|
||||
JLOG(j.warn()) << "OptionExercise: EXERCISE CALL";
|
||||
|
||||
STAmount hBalance = mSourceBalance;
|
||||
|
||||
// subtract the total value from the buyer
|
||||
// add the total value to the writer
|
||||
if (isXRP(totalValue))
|
||||
{
|
||||
if (mSourceBalance < totalValue.xrp())
|
||||
return tecUNFUNDED_PAYMENT;
|
||||
|
||||
// 1.
|
||||
hBalance -= totalValue.xrp();
|
||||
if (hBalance < beast::zero || hBalance > mSourceBalance)
|
||||
return tecINTERNAL;
|
||||
|
||||
// 2.
|
||||
STAmount wBalance = sleOppAcc->getFieldAmount(sfBalance);
|
||||
STAmount prior = wBalance;
|
||||
wBalance += totalValue.xrp();
|
||||
if (wBalance < beast::zero || wBalance < prior)
|
||||
return tecINTERNAL;
|
||||
sleOppAcc->setFieldAmount(sfBalance, wBalance);
|
||||
}
|
||||
else
|
||||
{
|
||||
// 1. & 2.
|
||||
TER canBuyerXfer = trustTransferAllowed(
|
||||
ctx_.view(),
|
||||
std::vector<AccountID>{srcAccID, oppAccID},
|
||||
totalValue.issue(),
|
||||
j);
|
||||
|
||||
if (!isTesSuccess(canBuyerXfer))
|
||||
{
|
||||
return canBuyerXfer;
|
||||
}
|
||||
|
||||
STAmount availableBuyerFunds{accountFunds(
|
||||
ctx_.view(), srcAccID, totalValue, fhZERO_IF_FROZEN, j)};
|
||||
|
||||
if (availableBuyerFunds < totalValue)
|
||||
return tecUNFUNDED_PAYMENT;
|
||||
|
||||
if (TER result = accountSend(
|
||||
ctx_.view(), srcAccID, oppAccID, totalValue, j, true);
|
||||
!isTesSuccess(result))
|
||||
return result;
|
||||
}
|
||||
|
||||
// add the shares to the buyer
|
||||
if (isXRP(quantityShares))
|
||||
{
|
||||
STAmount prior = hBalance;
|
||||
hBalance += quantityShares.xrp();
|
||||
if (hBalance < beast::zero || hBalance < prior)
|
||||
return tecINTERNAL;
|
||||
sleSrcAcc->setFieldAmount(sfBalance, hBalance);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Rate lockedRate = ripple::Rate(slep->getFieldU32(sfTransferRate));
|
||||
// auto const issuerAccID = totalPremium.getIssuer();
|
||||
// auto const xferRate = transferRate(view(), issuerAccID);
|
||||
// // // update if issuer rate is less than locked rate
|
||||
// // if (xferRate < lockedRate)
|
||||
// // lockedRate = xferRate;
|
||||
|
||||
// all the significant complexity of checking the validity of this
|
||||
// transfer and ensuring the lines exist etc is hidden away in this
|
||||
// function, all we need to do is call it and return if unsuccessful.
|
||||
TER const result = trustTransferLockedBalance(
|
||||
ctx_.view(),
|
||||
account_, // txn signing account
|
||||
sleOppAcc, // src account
|
||||
sleSrcAcc, // dst account
|
||||
quantityShares, // xfer amount
|
||||
-1,
|
||||
parityRate,
|
||||
j_,
|
||||
WetRun // wet run;
|
||||
);
|
||||
if (!isTesSuccess(result))
|
||||
return result;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 1: {
|
||||
JLOG(j.warn()) << "OptionExercise: EXERCISE PUT";
|
||||
if (isXRP(quantityShares))
|
||||
{
|
||||
// add the total value to the holder
|
||||
{
|
||||
STAmount hBalance = mSourceBalance;
|
||||
hBalance += totalValue.xrp();
|
||||
if (hBalance < beast::zero || hBalance < mSourceBalance)
|
||||
return tecINTERNAL;
|
||||
sleSrcAcc->setFieldAmount(sfBalance, hBalance);
|
||||
}
|
||||
|
||||
STAmount wBalance = sleOppAcc->getFieldAmount(sfBalance);
|
||||
if (wBalance < totalValue.xrp())
|
||||
return tecUNFUNDED_PAYMENT;
|
||||
// subtract the total value from the writer
|
||||
{
|
||||
STAmount prior = wBalance;
|
||||
wBalance -= totalValue.xrp();
|
||||
if (wBalance < beast::zero || wBalance > prior)
|
||||
return tecINTERNAL;
|
||||
}
|
||||
|
||||
// add the shares to the writer
|
||||
{
|
||||
STAmount prior = wBalance;
|
||||
wBalance += quantityShares.xrp();
|
||||
if (wBalance < beast::zero || wBalance < prior)
|
||||
return tecINTERNAL;
|
||||
}
|
||||
sleOppAcc->setFieldAmount(sfBalance, wBalance);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return tecINTERNAL;
|
||||
}
|
||||
|
||||
// apply
|
||||
ctx_.view().update(sleOppAcc);
|
||||
ctx_.view().update(sleSrcAcc);
|
||||
ctx_.view().erase(sleSealedOffer);
|
||||
ctx_.view().erase(sleOptionOffer);
|
||||
// sb.apply(ctx_.rawView());
|
||||
return tesSUCCESS;
|
||||
}
|
||||
|
||||
XRPAmount
|
||||
OptionExercise::calculateBaseFee(ReadView const& view, STTx const& tx)
|
||||
{
|
||||
return Transactor::calculateBaseFee(view, tx);
|
||||
}
|
||||
|
||||
} // namespace ripple
|
||||
@@ -1,54 +0,0 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2024 XRPL-Labs
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef RIPPLE_TX_OPTIONEXECUTE_H_INCLUDED
|
||||
#define RIPPLE_TX_OPTIONEXECUTE_H_INCLUDED
|
||||
|
||||
#include <ripple/app/tx/impl/Transactor.h>
|
||||
#include <ripple/basics/Log.h>
|
||||
#include <ripple/core/Config.h>
|
||||
#include <ripple/protocol/Indexes.h>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
class OptionExercise : public Transactor
|
||||
{
|
||||
public:
|
||||
static constexpr ConsequencesFactoryType ConsequencesFactory{Custom};
|
||||
|
||||
explicit OptionExercise(ApplyContext& ctx) : Transactor(ctx)
|
||||
{
|
||||
}
|
||||
|
||||
static XRPAmount
|
||||
calculateBaseFee(ReadView const& view, STTx const& tx);
|
||||
|
||||
static TxConsequences
|
||||
makeTxConsequences(PreflightContext const& ctx);
|
||||
|
||||
static NotTEC
|
||||
preflight(PreflightContext const& ctx);
|
||||
|
||||
TER
|
||||
doApply() override;
|
||||
};
|
||||
|
||||
} // namespace ripple
|
||||
|
||||
#endif
|
||||
@@ -1,109 +0,0 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2024 XRPL-Labs
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#include <ripple/app/tx/impl/OptionList.h>
|
||||
#include <ripple/basics/Log.h>
|
||||
#include <ripple/ledger/ApplyView.h>
|
||||
#include <ripple/ledger/View.h>
|
||||
#include <ripple/protocol/Feature.h>
|
||||
#include <ripple/protocol/Indexes.h>
|
||||
#include <ripple/protocol/STAccount.h>
|
||||
#include <ripple/protocol/TxFlags.h>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
TxConsequences
|
||||
OptionList::makeTxConsequences(PreflightContext const& ctx)
|
||||
{
|
||||
return TxConsequences{ctx.tx, TxConsequences::normal};
|
||||
}
|
||||
|
||||
NotTEC
|
||||
OptionList::preflight(PreflightContext const& ctx)
|
||||
{
|
||||
if (auto const ret = preflight1(ctx); !isTesSuccess(ret))
|
||||
return ret;
|
||||
|
||||
JLOG(ctx.j.warn()) << (ctx.tx.getFlags()) << "\n";
|
||||
JLOG(ctx.j.warn()) << (ctx.tx.getFlags() & tfUniversalMask) << "\n";
|
||||
if (ctx.tx.getFlags() & tfUniversalMask)
|
||||
{
|
||||
// There are no flags (other than universal).
|
||||
JLOG(ctx.j.warn()) << "Malformed transaction: Invalid flags set.";
|
||||
return temINVALID_FLAG;
|
||||
}
|
||||
}
|
||||
|
||||
TER
|
||||
OptionList::doApply()
|
||||
{
|
||||
if (!view().rules().enabled(featureOptions))
|
||||
return temDISABLED;
|
||||
|
||||
Sandbox sb(&ctx_.view());
|
||||
|
||||
beast::Journal const& j = ctx_.journal;
|
||||
|
||||
AccountID const srcAccID = ctx_.tx.getAccountID(sfAccount);
|
||||
std::uint32_t const expiration = ctx_.tx.getFieldU32(sfExpiration);
|
||||
STAmount const strikePrice = ctx_.tx.getFieldAmount(sfStrikePrice);
|
||||
AccountID const issuer = ctx_.tx.getAccountID(sfIssuer);
|
||||
auto const currency = ctx_.tx.getFieldH160(sfCurrency);
|
||||
|
||||
auto sleSrcAcc = sb.peek(keylet::account(srcAccID));
|
||||
if (!sleSrcAcc)
|
||||
return terNO_ACCOUNT;
|
||||
|
||||
std::optional<Keylet> const optionKeylet = keylet::option(strikePrice.getIssuer(), strikePrice.getCurrency(), strikePrice.mantissa(), expiration);
|
||||
if (sb.exists(*optionKeylet))
|
||||
return tecDUPLICATE;
|
||||
|
||||
auto const sleOption = std::make_shared<SLE>(*optionKeylet);
|
||||
|
||||
auto const newPage = sb.dirInsert(
|
||||
keylet::ownerDir(strikePrice.getIssuer()),
|
||||
*optionKeylet,
|
||||
describeOwnerDir(strikePrice.getIssuer()));
|
||||
|
||||
JLOG(j_.trace()) << "Adding Option to owner directory "
|
||||
<< to_string(optionKeylet->key) << ": "
|
||||
<< (newPage ? "success" : "failure");
|
||||
|
||||
if (!newPage)
|
||||
return tecDIR_FULL;
|
||||
|
||||
(*sleOption)[sfOwnerNode] = *newPage;
|
||||
(*sleOption)[sfStrikePrice] = strikePrice;
|
||||
(*sleOption)[sfIssuer] = issuer;
|
||||
(*sleOption)[sfCurrency] = currency;
|
||||
(*sleOption)[sfExpiration] = expiration;
|
||||
|
||||
// apply
|
||||
sb.insert(sleOption);
|
||||
sb.apply(ctx_.rawView());
|
||||
return tesSUCCESS;
|
||||
}
|
||||
|
||||
XRPAmount
|
||||
OptionList::calculateBaseFee(ReadView const& view, STTx const& tx)
|
||||
{
|
||||
return Transactor::calculateBaseFee(view, tx);
|
||||
}
|
||||
|
||||
} // namespace ripple
|
||||
@@ -23,6 +23,9 @@
|
||||
#include <ripple/ledger/View.h>
|
||||
#include <ripple/protocol/Feature.h>
|
||||
#include <ripple/protocol/Indexes.h>
|
||||
#include <ripple/protocol/TxFlags.h>
|
||||
#include <ripple/protocol/st.h>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
TxConsequences
|
||||
|
||||
105
src/ripple/app/tx/impl/SetHookDefinition.cpp
Normal file
105
src/ripple/app/tx/impl/SetHookDefinition.cpp
Normal file
@@ -0,0 +1,105 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2012, 2013 Ripple Labs Inc.
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#include <ripple/app/tx/impl/SetHookDefinition.h>
|
||||
#include <ripple/basics/Log.h>
|
||||
#include <ripple/protocol/Feature.h>
|
||||
#include <ripple/protocol/TxFlags.h>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
XRPAmount
|
||||
SetHookDefinition::calculateBaseFee(ReadView const& view, STTx const& tx)
|
||||
{
|
||||
return Transactor::calculateBaseFee(view, tx);
|
||||
}
|
||||
|
||||
NotTEC
|
||||
SetHookDefinition::preflight(PreflightContext const& ctx)
|
||||
{
|
||||
// if (!ctx.rules.enabled(featureHooksUpdate2))
|
||||
// return temDISABLED;
|
||||
|
||||
if (auto const ret = preflight1(ctx); !isTesSuccess(ret))
|
||||
return ret;
|
||||
|
||||
return preflight2(ctx);
|
||||
}
|
||||
|
||||
TER
|
||||
SetHookDefinition::preclaim(PreclaimContext const& ctx)
|
||||
{
|
||||
// if (!ctx.view.rules().enabled(featureHooksUpdate2))
|
||||
// return temDISABLED;
|
||||
|
||||
return tesSUCCESS;
|
||||
}
|
||||
|
||||
TER
|
||||
SetHookDefinition::doApply()
|
||||
{
|
||||
auto j = ctx_.app.journal("View");
|
||||
Sandbox sb(&ctx_.view());
|
||||
auto const sle = sb.read(keylet::account(account_));
|
||||
if (!sle)
|
||||
return tefINTERNAL;
|
||||
|
||||
ripple::Blob wasmBytes = ctx_.tx.getFieldVL(sfCreateCode);
|
||||
|
||||
if (wasmBytes.size() > hook::maxHookWasmSize())
|
||||
{
|
||||
JLOG(j.warn()) << "Malformed transaction: SetHookDefinition operation "
|
||||
"would create blob larger than max";
|
||||
return tecINTERNAL;
|
||||
}
|
||||
|
||||
auto const createHookHash =
|
||||
ripple::sha512Half_s(ripple::Slice(wasmBytes.data(), wasmBytes.size()));
|
||||
|
||||
Keylet keylet = ripple::keylet::hookDefinition(
|
||||
account_, ctx_.tx.getFieldU32(sfSequence));
|
||||
auto newHookDef = std::make_shared<SLE>(keylet);
|
||||
newHookDef->setFieldH256(sfHookHash, createHookHash);
|
||||
newHookDef->setAccountID(sfOwner, account_);
|
||||
newHookDef->setFieldH256(sfHookOn, ctx_.tx.getFieldH256(sfHookOn));
|
||||
newHookDef->setFieldH256(sfHookNamespace, ctx_.tx.getFieldH256(sfHookOn));
|
||||
newHookDef->setFieldArray(
|
||||
sfHookParameters,
|
||||
ctx_.tx.isFieldPresent(sfHookParameters)
|
||||
? ctx_.tx.getFieldArray(sfHookParameters)
|
||||
: STArray{});
|
||||
newHookDef->setFieldU16(
|
||||
sfHookApiVersion, ctx_.tx.getFieldU16(sfHookApiVersion));
|
||||
newHookDef->setFieldVL(sfCreateCode, wasmBytes);
|
||||
newHookDef->setFieldH256(sfHookSetTxnID, ctx_.tx.getTransactionID());
|
||||
newHookDef->setFieldU64(sfReferenceCount, 0);
|
||||
newHookDef->setFieldU32(sfFlags, hsfMUTALBE);
|
||||
if (ctx_.tx.isFieldPresent(sfHookGrants))
|
||||
{
|
||||
auto const& grants = ctx_.tx.getFieldArray(sfHookGrants);
|
||||
if (!grants.empty())
|
||||
newHookDef->setFieldArray(sfHookGrants, grants);
|
||||
}
|
||||
|
||||
sb.update(newHookDef);
|
||||
sb.apply(ctx_.rawView());
|
||||
return tesSUCCESS;
|
||||
}
|
||||
|
||||
} // namespace ripple
|
||||
@@ -1,7 +1,7 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2024 XRPL-Labs
|
||||
Copyright (c) 2012, 2013 Ripple Labs Inc.
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
@@ -17,34 +17,34 @@
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef RIPPLE_TX_OPTIONLIST_H_INCLUDED
|
||||
#define RIPPLE_TX_OPTIONLIST_H_INCLUDED
|
||||
#ifndef RIPPLE_TX_SETHOOKDEFINITION_H_INCLUDED
|
||||
#define RIPPLE_TX_SETHOOKDEFINITION_H_INCLUDED
|
||||
|
||||
#include <ripple/app/tx/impl/Transactor.h>
|
||||
#include <ripple/basics/Log.h>
|
||||
#include <ripple/core/Config.h>
|
||||
#include <ripple/protocol/Indexes.h>
|
||||
#include <ripple/protocol/TxFlags.h>
|
||||
#include <ripple/protocol/UintTypes.h>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
class OptionList : public Transactor
|
||||
class SetHookDefinition : public Transactor
|
||||
{
|
||||
public:
|
||||
static constexpr ConsequencesFactoryType ConsequencesFactory{Custom};
|
||||
static constexpr ConsequencesFactoryType ConsequencesFactory{Blocker};
|
||||
|
||||
explicit OptionList(ApplyContext& ctx) : Transactor(ctx)
|
||||
explicit SetHookDefinition(ApplyContext& ctx) : Transactor(ctx)
|
||||
{
|
||||
}
|
||||
|
||||
static XRPAmount
|
||||
calculateBaseFee(ReadView const& view, STTx const& tx);
|
||||
|
||||
static TxConsequences
|
||||
makeTxConsequences(PreflightContext const& ctx);
|
||||
|
||||
static NotTEC
|
||||
preflight(PreflightContext const& ctx);
|
||||
|
||||
static TER
|
||||
preclaim(PreclaimContext const& ctx);
|
||||
|
||||
TER
|
||||
doApply() override;
|
||||
};
|
||||
@@ -153,8 +153,10 @@ SetSignerList::preCompute()
|
||||
// NOTE: This way of computing the OwnerCount associated with a SignerList
|
||||
// is valid until the featureMultiSignReserve amendment passes. Once it
|
||||
// passes then just 1 OwnerCount is associated with a SignerList.
|
||||
static int
|
||||
signerCountBasedOwnerCountDelta(std::size_t entryCount, Rules const& rules)
|
||||
int
|
||||
SetSignerList::signerCountBasedOwnerCountDelta(
|
||||
std::size_t entryCount,
|
||||
Rules const& rules)
|
||||
{
|
||||
// We always compute the full change in OwnerCount, taking into account:
|
||||
// o The fact that we're adding/removing a SignerList and
|
||||
@@ -176,8 +178,8 @@ signerCountBasedOwnerCountDelta(std::size_t entryCount, Rules const& rules)
|
||||
return 2 + static_cast<int>(entryCount);
|
||||
}
|
||||
|
||||
static TER
|
||||
removeSignersFromLedger(
|
||||
TER
|
||||
SetSignerList::removeSignersFromLedger(
|
||||
Application& app,
|
||||
ApplyView& view,
|
||||
Keylet const& accountKeylet,
|
||||
|
||||
@@ -71,6 +71,18 @@ public:
|
||||
AccountID const& account,
|
||||
beast::Journal j);
|
||||
|
||||
static TER
|
||||
removeSignersFromLedger(
|
||||
Application& app,
|
||||
ApplyView& view,
|
||||
Keylet const& accountKeylet,
|
||||
Keylet const& ownerDirKeylet,
|
||||
Keylet const& signerListKeylet,
|
||||
beast::Journal j);
|
||||
|
||||
static int
|
||||
signerCountBasedOwnerCountDelta(std::size_t entryCount, Rules const& rules);
|
||||
|
||||
private:
|
||||
static void
|
||||
writeSignersToSLE(
|
||||
|
||||
@@ -38,18 +38,17 @@
|
||||
#include <ripple/app/tx/impl/NFTokenCancelOffer.h>
|
||||
#include <ripple/app/tx/impl/NFTokenCreateOffer.h>
|
||||
#include <ripple/app/tx/impl/NFTokenMint.h>
|
||||
#include <ripple/app/tx/impl/OptionCreate.h>
|
||||
#include <ripple/app/tx/impl/OptionExercise.h>
|
||||
#include <ripple/app/tx/impl/OptionList.h>
|
||||
#include <ripple/app/tx/impl/PayChan.h>
|
||||
#include <ripple/app/tx/impl/Payment.h>
|
||||
#include <ripple/app/tx/impl/Remit.h>
|
||||
#include <ripple/app/tx/impl/SetAccount.h>
|
||||
#include <ripple/app/tx/impl/SetHook.h>
|
||||
#include <ripple/app/tx/impl/SetHookDefinition.h>
|
||||
#include <ripple/app/tx/impl/SetRegularKey.h>
|
||||
#include <ripple/app/tx/impl/SetSignerList.h>
|
||||
#include <ripple/app/tx/impl/SetTrust.h>
|
||||
#include <ripple/app/tx/impl/URIToken.h>
|
||||
#include <ripple/app/tx/impl/XahauGenesis.h>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
@@ -127,12 +126,6 @@ invoke_preflight(PreflightContext const& ctx)
|
||||
return invoke_preflight_helper<EscrowFinish>(ctx);
|
||||
case ttESCROW_CANCEL:
|
||||
return invoke_preflight_helper<EscrowCancel>(ctx);
|
||||
case ttOPTION_CREATE:
|
||||
return invoke_preflight_helper<OptionCreate>(ctx);
|
||||
case ttOPTION_EXERCISE:
|
||||
return invoke_preflight_helper<OptionExercise>(ctx);
|
||||
case ttOPTION_LIST:
|
||||
return invoke_preflight_helper<OptionList>(ctx);
|
||||
case ttPAYCHAN_CLAIM:
|
||||
return invoke_preflight_helper<PayChanClaim>(ctx);
|
||||
case ttPAYCHAN_CREATE:
|
||||
@@ -183,6 +176,8 @@ invoke_preflight(PreflightContext const& ctx)
|
||||
case ttURITOKEN_CREATE_SELL_OFFER:
|
||||
case ttURITOKEN_CANCEL_SELL_OFFER:
|
||||
return invoke_preflight_helper<URIToken>(ctx);
|
||||
case ttHOOK_SET_DEFINITION:
|
||||
return invoke_preflight_helper<SetHookDefinition>(ctx);
|
||||
default:
|
||||
assert(false);
|
||||
return {temUNKNOWN, TxConsequences{temUNKNOWN}};
|
||||
@@ -254,12 +249,6 @@ invoke_preclaim(PreclaimContext const& ctx)
|
||||
return invoke_preclaim<EscrowFinish>(ctx);
|
||||
case ttESCROW_CANCEL:
|
||||
return invoke_preclaim<EscrowCancel>(ctx);
|
||||
case ttOPTION_CREATE:
|
||||
return invoke_preclaim<OptionCreate>(ctx);
|
||||
case ttOPTION_EXERCISE:
|
||||
return invoke_preclaim<OptionExercise>(ctx);
|
||||
case ttOPTION_LIST:
|
||||
return invoke_preclaim<OptionList>(ctx);
|
||||
case ttPAYCHAN_CLAIM:
|
||||
return invoke_preclaim<PayChanClaim>(ctx);
|
||||
case ttPAYCHAN_CREATE:
|
||||
@@ -310,6 +299,8 @@ invoke_preclaim(PreclaimContext const& ctx)
|
||||
case ttURITOKEN_CREATE_SELL_OFFER:
|
||||
case ttURITOKEN_CANCEL_SELL_OFFER:
|
||||
return invoke_preclaim<URIToken>(ctx);
|
||||
case ttHOOK_SET_DEFINITION:
|
||||
return invoke_preclaim<SetHookDefinition>(ctx);
|
||||
default:
|
||||
assert(false);
|
||||
return temUNKNOWN;
|
||||
@@ -343,12 +334,6 @@ invoke_calculateBaseFee(ReadView const& view, STTx const& tx)
|
||||
return EscrowFinish::calculateBaseFee(view, tx);
|
||||
case ttESCROW_CANCEL:
|
||||
return EscrowCancel::calculateBaseFee(view, tx);
|
||||
case ttOPTION_CREATE:
|
||||
return OptionCreate::calculateBaseFee(view, tx);
|
||||
case ttOPTION_EXERCISE:
|
||||
return OptionExercise::calculateBaseFee(view, tx);
|
||||
case ttOPTION_LIST:
|
||||
return OptionList::calculateBaseFee(view, tx);
|
||||
case ttPAYCHAN_CLAIM:
|
||||
return PayChanClaim::calculateBaseFee(view, tx);
|
||||
case ttPAYCHAN_CREATE:
|
||||
@@ -399,6 +384,8 @@ invoke_calculateBaseFee(ReadView const& view, STTx const& tx)
|
||||
case ttURITOKEN_CREATE_SELL_OFFER:
|
||||
case ttURITOKEN_CANCEL_SELL_OFFER:
|
||||
return URIToken::calculateBaseFee(view, tx);
|
||||
case ttHOOK_SET_DEFINITION:
|
||||
return SetHookDefinition::calculateBaseFee(view, tx);
|
||||
default:
|
||||
return XRPAmount{0};
|
||||
}
|
||||
@@ -492,18 +479,6 @@ invoke_apply(ApplyContext& ctx)
|
||||
EscrowCancel p(ctx);
|
||||
return p();
|
||||
}
|
||||
case ttOPTION_CREATE: {
|
||||
OptionCreate p(ctx);
|
||||
return p();
|
||||
}
|
||||
case ttOPTION_EXERCISE: {
|
||||
OptionExercise p(ctx);
|
||||
return p();
|
||||
}
|
||||
case ttOPTION_LIST: {
|
||||
OptionList p(ctx);
|
||||
return p();
|
||||
}
|
||||
case ttPAYCHAN_CLAIM: {
|
||||
PayChanClaim p(ctx);
|
||||
return p();
|
||||
@@ -596,6 +571,10 @@ invoke_apply(ApplyContext& ctx)
|
||||
URIToken p(ctx);
|
||||
return p();
|
||||
}
|
||||
case ttHOOK_SET_DEFINITION: {
|
||||
SetHookDefinition p(ctx);
|
||||
return p();
|
||||
}
|
||||
default:
|
||||
assert(false);
|
||||
return {temUNKNOWN, false};
|
||||
|
||||
@@ -277,7 +277,7 @@ public:
|
||||
Keylet const& key,
|
||||
std::function<void(std::shared_ptr<SLE> const&)> const& describe)
|
||||
{
|
||||
if (key.type != ltOFFER && key.type != ltOPTION_OFFER)
|
||||
if (key.type != ltOFFER)
|
||||
{
|
||||
assert(!"Only Offers are appended to book directories. "
|
||||
"Call dirInsert() instead.");
|
||||
|
||||
@@ -21,13 +21,6 @@
|
||||
#include <ripple/ledger/detail/ApplyViewBase.h>
|
||||
#include <ripple/protocol/STAccount.h>
|
||||
|
||||
// #include <ripple/app/paths/impl/AmountSpec.h>
|
||||
// #include <ripple/ledger/PaymentSandbox.h>
|
||||
// #include <ripple/ledger/View.h>
|
||||
// #include <ripple/protocol/Feature.h>
|
||||
// #include <ripple/protocol/SField.h>
|
||||
// #include <ripple/protocol/STAccount.h>
|
||||
|
||||
namespace ripple {
|
||||
namespace detail {
|
||||
|
||||
|
||||
@@ -358,7 +358,7 @@ extern uint256 const fixXahauV2;
|
||||
extern uint256 const featureRemit;
|
||||
extern uint256 const featureZeroB2M;
|
||||
extern uint256 const fixNSDelete;
|
||||
extern uint256 const featureOptions;
|
||||
extern uint256 const featureHooksUpdate2;
|
||||
|
||||
} // namespace ripple
|
||||
|
||||
|
||||
@@ -62,6 +62,9 @@ emittedTxn(uint256 const& id) noexcept;
|
||||
Keylet
|
||||
hookDefinition(uint256 const& hash) noexcept;
|
||||
|
||||
Keylet
|
||||
hookDefinition(AccountID const& account, std::uint32_t seq) noexcept;
|
||||
|
||||
Keylet
|
||||
hook(AccountID const& id) noexcept;
|
||||
|
||||
@@ -297,24 +300,6 @@ import_vlseq(PublicKey const& key) noexcept;
|
||||
Keylet
|
||||
uritoken(AccountID const& issuer, Blob const& uri);
|
||||
|
||||
Keylet
|
||||
option(AccountID const& issuer, Currency const& currency, std::uint64_t strike, std::uint32_t expiration) noexcept;
|
||||
|
||||
Keylet
|
||||
optionBook(AccountID const& issuer, Currency const& currency, std::uint64_t strike, std::uint32_t expiration) noexcept;
|
||||
|
||||
Keylet
|
||||
optionOffer(AccountID const& id, std::uint32_t seq) noexcept;
|
||||
|
||||
inline Keylet
|
||||
optionOffer(uint256 const& key) noexcept
|
||||
{
|
||||
return {ltOPTION_OFFER, key};
|
||||
}
|
||||
|
||||
Keylet
|
||||
optionQuality(Keylet const& k, std::uint64_t q) noexcept;
|
||||
|
||||
} // namespace keylet
|
||||
|
||||
// Everything below is deprecated and should be removed in favor of keylets:
|
||||
@@ -329,18 +314,6 @@ getQualityNext(uint256 const& uBase);
|
||||
std::uint64_t
|
||||
getQuality(uint256 const& uBase);
|
||||
|
||||
uint256
|
||||
getOptionBookBase(AccountID const& issuer, Currency const& currency, std::uint64_t strike, std::uint32_t expiration);
|
||||
|
||||
uint256
|
||||
getOptionQualityNext(uint256 const& uBase);
|
||||
|
||||
// VFALCO This name could be better
|
||||
std::uint64_t
|
||||
getOptionQuality(uint256 const& uBase);
|
||||
|
||||
/** The initial directory page for a specific quality */
|
||||
|
||||
uint256
|
||||
getTicketIndex(AccountID const& account, std::uint32_t uSequence);
|
||||
|
||||
|
||||
@@ -254,18 +254,6 @@ enum LedgerEntryType : std::uint16_t
|
||||
\sa keylet::emitted
|
||||
*/
|
||||
ltEMITTED_TXN = 'E',
|
||||
|
||||
/** A ledger object
|
||||
|
||||
\sa keylet::broker_state
|
||||
*/
|
||||
ltOPTION = 'X',
|
||||
|
||||
/** A ledger object
|
||||
|
||||
\sa keylet::broker_state
|
||||
*/
|
||||
ltOPTION_OFFER = 'y',
|
||||
};
|
||||
// clang-format off
|
||||
|
||||
@@ -327,12 +315,6 @@ enum LedgerSpecificFlags {
|
||||
|
||||
// ltURI_TOKEN
|
||||
lsfBurnable = 0x00000001, // True, issuer can burn the token
|
||||
|
||||
// ltOPTION_OFFER
|
||||
lsfType = 0x00010000,
|
||||
lsfAction = 0x00020000,
|
||||
lsfPosition = 0x00040000,
|
||||
lsfCovered = 0x00080000,
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
@@ -1,103 +0,0 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2012, 2013 Ripple Labs Inc.
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef RIPPLE_PROTOCOL_OPTION_H_INCLUDED
|
||||
#define RIPPLE_PROTOCOL_OPTION_H_INCLUDED
|
||||
|
||||
#include <ripple/basics/CountedObject.h>
|
||||
#include <ripple/protocol/Issue.h>
|
||||
#include <boost/utility/base_from_member.hpp>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
class Option final : public CountedObject<Option>
|
||||
{
|
||||
public:
|
||||
Issue issue;
|
||||
uint64_t strike;
|
||||
uint32_t expiration;
|
||||
|
||||
Option()
|
||||
{
|
||||
}
|
||||
|
||||
Option(
|
||||
Issue issue_,
|
||||
uint64_t strike_,
|
||||
uint32_t expiration_)
|
||||
: issue(issue_)
|
||||
, strike(strike_)
|
||||
, expiration(expiration_)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
std::string
|
||||
to_string(Option const& option);
|
||||
|
||||
std::ostream&
|
||||
operator<<(std::ostream& os, Option const& x);
|
||||
|
||||
template <class Hasher>
|
||||
void
|
||||
hash_append(Hasher& h, Option const& o)
|
||||
{
|
||||
using beast::hash_append;
|
||||
hash_append(h, o.issue, o.strike, o.expiration);
|
||||
}
|
||||
|
||||
/** Equality comparison. */
|
||||
/** @{ */
|
||||
[[nodiscard]] inline constexpr bool
|
||||
operator==(Option const& lhs, Option const& rhs)
|
||||
{
|
||||
return (lhs.issue == rhs.issue) && (lhs.strike == rhs.strike) && (lhs.expiration == rhs.expiration);
|
||||
}
|
||||
/** @} */
|
||||
|
||||
/** Strict weak ordering. */
|
||||
/** @{ */
|
||||
[[nodiscard]] inline constexpr std::weak_ordering
|
||||
operator<=>(Option const& lhs, Option const& rhs)
|
||||
{
|
||||
if (auto const c{lhs.strike <=> rhs.strike}; c != 0)
|
||||
return c;
|
||||
return lhs.strike <=> rhs.strike;
|
||||
}
|
||||
/** @} */
|
||||
|
||||
} // namespace ripple
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace boost {
|
||||
|
||||
template <>
|
||||
struct hash<ripple::Option> : std::hash<ripple::Option>
|
||||
{
|
||||
explicit hash() = default;
|
||||
|
||||
using Base = std::hash<ripple::Option>;
|
||||
// VFALCO NOTE broken in vs2012
|
||||
// using Base::Base; // inherit ctors
|
||||
};
|
||||
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
@@ -410,8 +410,6 @@ extern SF_UINT32 const sfRewardLgrLast;
|
||||
extern SF_UINT32 const sfFirstNFTokenSequence;
|
||||
extern SF_UINT32 const sfImportSequence;
|
||||
extern SF_UINT32 const sfXahauActivationLgrSeq;
|
||||
extern SF_UINT32 const sfQuantity;
|
||||
extern SF_UINT32 const sfOpenInterest;
|
||||
|
||||
// 64-bit integers (common)
|
||||
extern SF_UINT64 const sfIndexNext;
|
||||
@@ -444,7 +442,6 @@ extern SF_UINT160 const sfTakerPaysCurrency;
|
||||
extern SF_UINT160 const sfTakerPaysIssuer;
|
||||
extern SF_UINT160 const sfTakerGetsCurrency;
|
||||
extern SF_UINT160 const sfTakerGetsIssuer;
|
||||
extern SF_UINT160 const sfCurrency;
|
||||
|
||||
// 256-bit (common)
|
||||
extern SF_UINT256 const sfLedgerHash;
|
||||
@@ -486,8 +483,6 @@ extern SF_UINT256 const sfURITokenID;
|
||||
extern SF_UINT256 const sfGovernanceFlags;
|
||||
extern SF_UINT256 const sfGovernanceMarks;
|
||||
extern SF_UINT256 const sfEmittedTxnID;
|
||||
extern SF_UINT256 const sfOptionID;
|
||||
extern SF_UINT256 const sfSwapID;
|
||||
|
||||
// currency amount (common)
|
||||
extern SF_AMOUNT const sfAmount;
|
||||
@@ -501,7 +496,6 @@ extern SF_AMOUNT const sfFee;
|
||||
extern SF_AMOUNT const sfSendMax;
|
||||
extern SF_AMOUNT const sfDeliverMin;
|
||||
extern SF_AMOUNT const sfLockedBalance;
|
||||
extern SF_AMOUNT const sfStrikePrice;
|
||||
|
||||
// currency amount (uncommon)
|
||||
extern SF_AMOUNT const sfMinimumOffer;
|
||||
|
||||
@@ -171,7 +171,8 @@ STValidation::STValidation(
|
||||
{
|
||||
if (checkSignature && !isValid())
|
||||
{
|
||||
JLOG(debugLog().error()) << "Invalid signature in validation";
|
||||
JLOG(debugLog().error()) << "Invalid signature in validation: "
|
||||
<< getJson(JsonOptions::none);
|
||||
Throw<std::runtime_error>("Invalid signature in validation");
|
||||
}
|
||||
|
||||
|
||||
@@ -190,21 +190,6 @@ enum ClaimRewardFlags : uint32_t {
|
||||
tfOptOut = 0x00000001,
|
||||
};
|
||||
|
||||
// OptionCreate flags:
|
||||
enum OptionCreateFlags : uint32_t {
|
||||
tfType = 0x00010000, // 0 Call 1 Put
|
||||
tfAction = 0x00020000, // 0 Buy 2 Sell
|
||||
tfPosition = 0x00040000, // 0 Open 4 Close
|
||||
};
|
||||
constexpr std::uint32_t tfOptionCreateMask =
|
||||
~(tfUniversal | tfType | tfAction | tfPosition);
|
||||
|
||||
// OptionExpire flags:
|
||||
enum OptionExpireFlags : uint32_t {
|
||||
tfOptionExpire = 0x00010000,
|
||||
};
|
||||
constexpr std::uint32_t tfOptionExpireMask = ~(tfUniversal | tfOptionExpire);
|
||||
|
||||
// clang-format on
|
||||
|
||||
} // namespace ripple
|
||||
|
||||
@@ -185,9 +185,7 @@ enum TxType : std::uint16_t
|
||||
ttUNL_MODIFY = 102,
|
||||
ttEMIT_FAILURE = 103,
|
||||
ttUNL_REPORT = 104,
|
||||
ttOPTION_LIST = 105,
|
||||
ttOPTION_CREATE = 106,
|
||||
ttOPTION_EXERCISE = 107,
|
||||
ttHOOK_SET_DEFINITION = 105,
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
|
||||
@@ -464,7 +464,7 @@ REGISTER_FIX (fixXahauV2, Supported::yes, VoteBehavior::De
|
||||
REGISTER_FEATURE(Remit, Supported::yes, VoteBehavior::DefaultNo);
|
||||
REGISTER_FEATURE(ZeroB2M, Supported::yes, VoteBehavior::DefaultNo);
|
||||
REGISTER_FIX (fixNSDelete, Supported::yes, VoteBehavior::DefaultNo);
|
||||
REGISTER_FEATURE(Options, Supported::yes, VoteBehavior::DefaultNo);
|
||||
REGISTER_FIX (HooksUpdate2, Supported::yes, VoteBehavior::DefaultNo);
|
||||
|
||||
// The following amendments are obsolete, but must remain supported
|
||||
// because they could potentially get enabled.
|
||||
|
||||
@@ -72,9 +72,6 @@ enum class LedgerNameSpace : std::uint16_t {
|
||||
URI_TOKEN = 'U',
|
||||
IMPORT_VLSEQ = 'I',
|
||||
UNL_REPORT = 'R',
|
||||
OPTION = 'X',
|
||||
OPTION_DIR = 'Y',
|
||||
OPTION_OFFER = 'y',
|
||||
|
||||
// No longer used or supported. Left here to reserve the space
|
||||
// to avoid accidental reuse.
|
||||
@@ -123,33 +120,6 @@ getQuality(uint256 const& uBase)
|
||||
return boost::endian::big_to_native(((std::uint64_t*)uBase.end())[-1]);
|
||||
}
|
||||
|
||||
uint256
|
||||
getOptionBookBase(AccountID const& issuer, Currency const& currency, std::uint64_t strike, std::uint32_t expiration)
|
||||
{
|
||||
auto const index = indexHash(
|
||||
LedgerNameSpace::BOOK_DIR,
|
||||
issuer, currency, strike, expiration);
|
||||
|
||||
// Return with quality 0.
|
||||
auto k = keylet::optionQuality({ltDIR_NODE, index}, 0);
|
||||
return k.key;
|
||||
}
|
||||
|
||||
uint256
|
||||
getOptionQualityNext(uint256 const& uBase)
|
||||
{
|
||||
static constexpr uint256 nextq(
|
||||
"0000000000000000000000000000000000000000000000010000000000000000");
|
||||
return uBase + nextq;
|
||||
}
|
||||
|
||||
std::uint64_t
|
||||
getOptionQuality(uint256 const& uBase)
|
||||
{
|
||||
// VFALCO [base_uint] This assumes a certain storage format
|
||||
return boost::endian::big_to_native(((std::uint64_t*)uBase.end())[-1]);
|
||||
}
|
||||
|
||||
uint256
|
||||
getTicketIndex(AccountID const& account, std::uint32_t ticketSeq)
|
||||
{
|
||||
@@ -201,6 +171,13 @@ hookDefinition(uint256 const& hash) noexcept
|
||||
ltHOOK_DEFINITION, indexHash(LedgerNameSpace::HOOK_DEFINITION, hash)};
|
||||
}
|
||||
|
||||
Keylet
|
||||
hookDefinition(AccountID const& account, std::uint32_t seq) noexcept
|
||||
{
|
||||
return {
|
||||
ltHOOK_DEFINITION, indexHash(LedgerNameSpace::HOOK_DEFINITION, account, seq)};
|
||||
}
|
||||
|
||||
Keylet
|
||||
hookState(AccountID const& id, uint256 const& key, uint256 const& ns) noexcept
|
||||
{
|
||||
@@ -473,42 +450,6 @@ uritoken(AccountID const& issuer, Blob const& uri)
|
||||
LedgerNameSpace::URI_TOKEN, issuer, Slice{uri.data(), uri.size()})};
|
||||
}
|
||||
|
||||
Keylet
|
||||
option(AccountID const& issuer, Currency const& currency, std::uint64_t strike, std::uint32_t expiration) noexcept
|
||||
{
|
||||
return {ltOPTION, indexHash(LedgerNameSpace::OPTION, issuer, currency, strike, expiration)};
|
||||
}
|
||||
|
||||
Keylet
|
||||
optionBook(AccountID const& issuer, Currency const& currency, std::uint64_t strike, std::uint32_t expiration) noexcept
|
||||
{
|
||||
return {ltDIR_NODE, getOptionBookBase(issuer, currency, strike, expiration)};
|
||||
}
|
||||
|
||||
Keylet
|
||||
optionQuality(Keylet const& k, std::uint64_t q) noexcept
|
||||
{
|
||||
assert(k.type == ltDIR_NODE);
|
||||
|
||||
// Indexes are stored in big endian format: they print as hex as stored.
|
||||
// Most significant bytes are first and the least significant bytes
|
||||
// represent adjacent entries. We place the quality, in big endian format,
|
||||
// in the 8 right most bytes; this way, incrementing goes to the next entry
|
||||
// for indexes.
|
||||
uint256 x = k.key;
|
||||
|
||||
// FIXME This is ugly and we can and should do better...
|
||||
((std::uint64_t*)x.end())[-1] = boost::endian::native_to_big(q);
|
||||
|
||||
return {ltDIR_NODE, x};
|
||||
}
|
||||
|
||||
Keylet
|
||||
optionOffer(AccountID const& id, std::uint32_t seq) noexcept
|
||||
{
|
||||
return {ltOPTION_OFFER, indexHash(LedgerNameSpace::OPTION_OFFER, id, seq)};
|
||||
}
|
||||
|
||||
} // namespace keylet
|
||||
|
||||
} // namespace ripple
|
||||
|
||||
@@ -90,7 +90,8 @@ InnerObjectFormats::InnerObjectFormats()
|
||||
{sfHookOn, soeREQUIRED},
|
||||
{sfHookApiVersion, soeREQUIRED},
|
||||
{sfFlags, soeREQUIRED},
|
||||
{sfFee, soeREQUIRED}});
|
||||
{sfFee, soeREQUIRED},
|
||||
{sfOwner, soeOPTIONAL}});
|
||||
|
||||
add(sfHook.jsonName.c_str(),
|
||||
sfHook.getCode(),
|
||||
|
||||
@@ -84,8 +84,6 @@ LedgerFormats::LedgerFormats()
|
||||
{sfIndexNext, soeOPTIONAL},
|
||||
{sfIndexPrevious, soeOPTIONAL},
|
||||
{sfNFTokenID, soeOPTIONAL},
|
||||
{sfBaseFee, soeOPTIONAL},
|
||||
{sfExpiration, soeOPTIONAL},
|
||||
},
|
||||
commonFields);
|
||||
|
||||
@@ -365,38 +363,6 @@ LedgerFormats::LedgerFormats()
|
||||
},
|
||||
commonFields);
|
||||
|
||||
add(jss::Option,
|
||||
ltOPTION,
|
||||
{
|
||||
{sfOwnerNode, soeREQUIRED},
|
||||
{sfStrikePrice, soeREQUIRED},
|
||||
{sfIssuer, soeREQUIRED},
|
||||
{sfCurrency, soeREQUIRED},
|
||||
{sfExpiration, soeREQUIRED},
|
||||
{sfPreviousTxnID, soeREQUIRED},
|
||||
{sfPreviousTxnLgrSeq, soeREQUIRED}
|
||||
},
|
||||
commonFields);
|
||||
|
||||
add(jss::OptionOffer,
|
||||
ltOPTION_OFFER,
|
||||
{
|
||||
{sfOwner, soeREQUIRED},
|
||||
{sfOwnerNode, soeREQUIRED},
|
||||
{sfOptionID, soeREQUIRED}, // OptionID
|
||||
{sfLockedBalance, soeREQUIRED}, // Locked Amount
|
||||
{sfAmount, soeREQUIRED}, // Premium
|
||||
{sfQuantity, soeREQUIRED}, // Quantity
|
||||
{sfOpenInterest, soeREQUIRED}, // To Seal
|
||||
{sfBookDirectory, soeREQUIRED},
|
||||
{sfBookNode, soeREQUIRED},
|
||||
{sfSwapID, soeOPTIONAL}, // MatchID
|
||||
{sfCheckID, soeOPTIONAL}, // SwapID
|
||||
{sfPreviousTxnID, soeREQUIRED},
|
||||
{sfPreviousTxnLgrSeq, soeREQUIRED}
|
||||
},
|
||||
commonFields);
|
||||
|
||||
// clang-format on
|
||||
}
|
||||
|
||||
|
||||
@@ -1,37 +0,0 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2012, 2013 Ripple Labs Inc.
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#include <ripple/protocol/Option.h>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
std::string
|
||||
to_string(Option const& option)
|
||||
{
|
||||
return to_string(option.issue) + "/" + to_string(option.strike) + "/" + to_string(option.expiration);
|
||||
}
|
||||
|
||||
std::ostream&
|
||||
operator<<(std::ostream& os, Option const& x)
|
||||
{
|
||||
os << to_string(x);
|
||||
return os;
|
||||
}
|
||||
|
||||
} // namespace ripple
|
||||
@@ -157,8 +157,6 @@ CONSTRUCT_TYPED_SFIELD(sfLockCount, "LockCount", UINT32,
|
||||
|
||||
CONSTRUCT_TYPED_SFIELD(sfFirstNFTokenSequence, "FirstNFTokenSequence", UINT32, 50);
|
||||
|
||||
CONSTRUCT_TYPED_SFIELD(sfOpenInterest, "OpenInterest", UINT32, 94);
|
||||
CONSTRUCT_TYPED_SFIELD(sfQuantity, "Quantity", UINT32, 95);
|
||||
CONSTRUCT_TYPED_SFIELD(sfXahauActivationLgrSeq, "XahauActivationLgrSeq",UINT32, 96);
|
||||
CONSTRUCT_TYPED_SFIELD(sfImportSequence, "ImportSequence", UINT32, 97);
|
||||
CONSTRUCT_TYPED_SFIELD(sfRewardTime, "RewardTime", UINT32, 98);
|
||||
@@ -197,7 +195,6 @@ CONSTRUCT_TYPED_SFIELD(sfTakerPaysCurrency, "TakerPaysCurrency", UINT160,
|
||||
CONSTRUCT_TYPED_SFIELD(sfTakerPaysIssuer, "TakerPaysIssuer", UINT160, 2);
|
||||
CONSTRUCT_TYPED_SFIELD(sfTakerGetsCurrency, "TakerGetsCurrency", UINT160, 3);
|
||||
CONSTRUCT_TYPED_SFIELD(sfTakerGetsIssuer, "TakerGetsIssuer", UINT160, 4);
|
||||
CONSTRUCT_TYPED_SFIELD(sfCurrency, "Currency", UINT160, 5);
|
||||
|
||||
// 256-bit (common)
|
||||
CONSTRUCT_TYPED_SFIELD(sfLedgerHash, "LedgerHash", UINT256, 1);
|
||||
@@ -239,8 +236,6 @@ CONSTRUCT_TYPED_SFIELD(sfURITokenID, "URITokenID", UINT256,
|
||||
CONSTRUCT_TYPED_SFIELD(sfGovernanceFlags, "GovernanceFlags", UINT256, 99);
|
||||
CONSTRUCT_TYPED_SFIELD(sfGovernanceMarks, "GovernanceMarks", UINT256, 98);
|
||||
CONSTRUCT_TYPED_SFIELD(sfEmittedTxnID, "EmittedTxnID", UINT256, 97);
|
||||
CONSTRUCT_TYPED_SFIELD(sfOptionID, "OptionID", UINT256, 96);
|
||||
CONSTRUCT_TYPED_SFIELD(sfSwapID, "SwapID", UINT256, 95);
|
||||
|
||||
// currency amount (common)
|
||||
CONSTRUCT_TYPED_SFIELD(sfAmount, "Amount", AMOUNT, 1);
|
||||
@@ -266,7 +261,6 @@ CONSTRUCT_TYPED_SFIELD(sfLockedBalance, "LockedBalance", AMOUNT,
|
||||
CONSTRUCT_TYPED_SFIELD(sfBaseFeeDrops, "BaseFeeDrops", AMOUNT, 22);
|
||||
CONSTRUCT_TYPED_SFIELD(sfReserveBaseDrops, "ReserveBaseDrops", AMOUNT, 23);
|
||||
CONSTRUCT_TYPED_SFIELD(sfReserveIncrementDrops, "ReserveIncrementDrops", AMOUNT, 24);
|
||||
CONSTRUCT_TYPED_SFIELD(sfStrikePrice, "StrikePrice", AMOUNT, 25);
|
||||
|
||||
// variable length (common)
|
||||
CONSTRUCT_TYPED_SFIELD(sfPublicKey, "PublicKey", VL, 1);
|
||||
|
||||
@@ -457,34 +457,16 @@ TxFormats::TxFormats()
|
||||
},
|
||||
commonFields);
|
||||
|
||||
add(jss::OptionList,
|
||||
ttOPTION_LIST,
|
||||
add(jss::SetHookDefinition,
|
||||
ttHOOK_SET_DEFINITION,
|
||||
{
|
||||
{sfStrikePrice, soeREQUIRED},
|
||||
{sfIssuer, soeREQUIRED},
|
||||
{sfCurrency, soeREQUIRED},
|
||||
{sfExpiration, soeREQUIRED},
|
||||
{sfTicketSequence, soeOPTIONAL},
|
||||
},
|
||||
commonFields);
|
||||
|
||||
add(jss::OptionCreate,
|
||||
ttOPTION_CREATE,
|
||||
{
|
||||
{sfOptionID, soeREQUIRED}, // Option ID
|
||||
{sfAmount, soeREQUIRED}, // Premium
|
||||
{sfQuantity, soeREQUIRED}, // Quantity
|
||||
{sfSwapID, soeOPTIONAL}, // Swap ID
|
||||
{sfTicketSequence, soeOPTIONAL},
|
||||
},
|
||||
commonFields);
|
||||
|
||||
add(jss::OptionExercise,
|
||||
ttOPTION_EXERCISE,
|
||||
{
|
||||
{sfOptionID, soeREQUIRED},
|
||||
{sfSwapID, soeOPTIONAL},
|
||||
{sfTicketSequence, soeOPTIONAL},
|
||||
{sfCreateCode, soeREQUIRED},
|
||||
{sfHookNamespace, soeREQUIRED},
|
||||
{sfHookParameters, soeOPTIONAL},
|
||||
{sfHookGrants, soeOPTIONAL},
|
||||
{sfHookOn, soeREQUIRED},
|
||||
{sfHookApiVersion, soeREQUIRED},
|
||||
{sfFlags, soeREQUIRED},
|
||||
},
|
||||
commonFields);
|
||||
}
|
||||
|
||||
@@ -111,13 +111,8 @@ JSS(Offer); // ledger type.
|
||||
JSS(OfferCancel); // transaction type.
|
||||
JSS(OfferCreate); // transaction type.
|
||||
JSS(OfferSequence); // field.
|
||||
JSS(Option); // ledger type.
|
||||
JSS(OptionCreate); // transaction type.
|
||||
JSS(OptionExercise); // transaction type.
|
||||
JSS(OptionList); // transaction type.
|
||||
JSS(OptionOffer); // ledger type.
|
||||
JSS(Paths); // in/out: TransactionSign
|
||||
JSS(PayChannel); // ledger type.E
|
||||
JSS(PayChannel); // ledger type.
|
||||
JSS(Payment); // transaction type.
|
||||
JSS(PaymentChannelClaim); // transaction type.
|
||||
JSS(PaymentChannelCreate); // transaction type.
|
||||
@@ -134,6 +129,7 @@ JSS(Sequence); // in/out: TransactionSign; field.
|
||||
JSS(SetFlag); // field.
|
||||
JSS(SetRegularKey); // transaction type.
|
||||
JSS(SetHook); // transaction type.
|
||||
JSS(SetHookDefinition); // transaction type.
|
||||
JSS(Hook); // ledger type.
|
||||
JSS(HookDefinition); // ledger type.
|
||||
JSS(HookState); // ledger type.
|
||||
@@ -515,7 +511,6 @@ JSS(open); // out: handlers/Ledger
|
||||
JSS(open_ledger_cost); // out: SubmitTransaction
|
||||
JSS(open_ledger_fee); // out: TxQ
|
||||
JSS(open_ledger_level); // out: TxQ
|
||||
JSS(option); // out: AccountObjects
|
||||
JSS(owner); // in: LedgerEntry, out: NetworkOPs
|
||||
JSS(owner_funds); // in/out: Ledger, NetworkOPs, AcceptedLedgerTx
|
||||
JSS(page_index);
|
||||
@@ -636,7 +631,6 @@ JSS(stop_history_tx_only); // in: Unsubscribe, stop history tx stream
|
||||
JSS(storedSeqs); // out: NodeToShardStatus
|
||||
JSS(streams); // in: Subscribe, Unsubscribe
|
||||
JSS(strict); // in: AccountCurrencies, AccountInfo
|
||||
JSS(strike_price); // in: NetworkOPs
|
||||
JSS(sub_index); // in: LedgerEntry
|
||||
JSS(subcommand); // in: PathFind
|
||||
JSS(success); // rpc
|
||||
|
||||
@@ -189,8 +189,8 @@ doAccountObjects(RPC::JsonContext& context)
|
||||
}
|
||||
}
|
||||
|
||||
// if (!ledger->exists(keylet::account(accountID)))
|
||||
// return rpcError(rpcACT_NOT_FOUND);
|
||||
if (!ledger->exists(keylet::account(accountID)))
|
||||
return rpcError(rpcACT_NOT_FOUND);
|
||||
|
||||
std::optional<std::vector<LedgerEntryType>> typeFilter;
|
||||
|
||||
@@ -208,7 +208,6 @@ doAccountObjects(RPC::JsonContext& context)
|
||||
{jss::hook, ltHOOK},
|
||||
{jss::payment_channel, ltPAYCHAN},
|
||||
{jss::uri_token, ltURI_TOKEN},
|
||||
{jss::option, ltOPTION},
|
||||
{jss::state, ltRIPPLE_STATE}};
|
||||
|
||||
typeFilter.emplace();
|
||||
|
||||
@@ -103,8 +103,6 @@ doNodeToShard(RPC::JsonContext&);
|
||||
Json::Value
|
||||
doNoRippleCheck(RPC::JsonContext&);
|
||||
Json::Value
|
||||
doOptionBookOffers(RPC::JsonContext&);
|
||||
Json::Value
|
||||
doOwnerInfo(RPC::JsonContext&);
|
||||
Json::Value
|
||||
doPathFind(RPC::JsonContext&);
|
||||
|
||||
@@ -1,160 +0,0 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2012-2014 Ripple Labs Inc.
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#include <ripple/app/main/Application.h>
|
||||
#include <ripple/app/misc/NetworkOPs.h>
|
||||
#include <ripple/basics/Log.h>
|
||||
#include <ripple/ledger/ReadView.h>
|
||||
#include <ripple/net/RPCErr.h>
|
||||
#include <ripple/protocol/ErrorCodes.h>
|
||||
#include <ripple/protocol/UintTypes.h>
|
||||
#include <ripple/protocol/jss.h>
|
||||
#include <ripple/resource/Fees.h>
|
||||
#include <ripple/rpc/Context.h>
|
||||
#include <ripple/rpc/impl/RPCHelpers.h>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
Json::Value
|
||||
doOptionBookOffers(RPC::JsonContext& context)
|
||||
{
|
||||
// VFALCO TODO Here is a terrible place for this kind of business
|
||||
// logic. It needs to be moved elsewhere and documented,
|
||||
// and encapsulated into a function.
|
||||
if (context.app.getJobQueue().getJobCountGE(jtCLIENT) > 200)
|
||||
return rpcError(rpcTOO_BUSY);
|
||||
|
||||
std::shared_ptr<ReadView const> lpLedger;
|
||||
auto jvResult = RPC::lookupLedger(lpLedger, context);
|
||||
|
||||
if (!lpLedger)
|
||||
return jvResult;
|
||||
|
||||
if (!context.params.isMember(jss::strike_price))
|
||||
return RPC::missing_field_error(jss::strike_price);
|
||||
|
||||
Json::Value const& strike_price = context.params[jss::strike_price];
|
||||
|
||||
if (!strike_price.isObjectOrNull())
|
||||
return RPC::object_field_error(jss::strike_price);
|
||||
|
||||
// if (!taker_gets.isObjectOrNull())
|
||||
// return RPC::object_field_error(jss::taker_gets);
|
||||
|
||||
if (!strike_price.isMember(jss::currency))
|
||||
return RPC::missing_field_error("strike_price.currency");
|
||||
|
||||
if (!strike_price[jss::currency].isString())
|
||||
return RPC::expected_field_error("strike_price.currency", "string");
|
||||
|
||||
// if (!taker_gets.isMember(jss::currency))
|
||||
// return RPC::missing_field_error("taker_gets.currency");
|
||||
|
||||
// if (!taker_gets[jss::currency].isString())
|
||||
// return RPC::expected_field_error("taker_gets.currency", "string");
|
||||
|
||||
Currency pay_currency;
|
||||
|
||||
if (!to_currency(pay_currency, strike_price[jss::currency].asString()))
|
||||
{
|
||||
JLOG(context.j.info()) << "Bad strike_price currency.";
|
||||
return RPC::make_error(
|
||||
rpcSRC_CUR_MALFORMED,
|
||||
"Invalid field 'strike_price.currency', bad currency.");
|
||||
}
|
||||
|
||||
AccountID pay_issuer;
|
||||
|
||||
if (strike_price.isMember(jss::issuer))
|
||||
{
|
||||
if (!strike_price[jss::issuer].isString())
|
||||
return RPC::expected_field_error("strike_price.issuer", "string");
|
||||
|
||||
if (!to_issuer(pay_issuer, strike_price[jss::issuer].asString()))
|
||||
return RPC::make_error(
|
||||
rpcSRC_ISR_MALFORMED,
|
||||
"Invalid field 'strike_price.issuer', bad issuer.");
|
||||
|
||||
if (pay_issuer == noAccount())
|
||||
return RPC::make_error(
|
||||
rpcSRC_ISR_MALFORMED,
|
||||
"Invalid field 'strike_price.issuer', bad issuer account one.");
|
||||
}
|
||||
else
|
||||
{
|
||||
pay_issuer = xrpAccount();
|
||||
}
|
||||
|
||||
std::optional<std::uint64_t> pay_value;
|
||||
if (strike_price.isMember(jss::value))
|
||||
{
|
||||
if (!strike_price[jss::value].isString())
|
||||
return RPC::expected_field_error("strike_price.value", "string");
|
||||
|
||||
pay_value = strike_price[jss::value].asInt();
|
||||
if (!pay_value)
|
||||
return RPC::invalid_field_error(jss::value);
|
||||
}
|
||||
|
||||
if (isXRP(pay_currency) && !isXRP(pay_issuer))
|
||||
return RPC::make_error(
|
||||
rpcSRC_ISR_MALFORMED,
|
||||
"Unneeded field 'taker_pays.issuer' for "
|
||||
"XRP currency specification.");
|
||||
|
||||
if (!isXRP(pay_currency) && isXRP(pay_issuer))
|
||||
return RPC::make_error(
|
||||
rpcSRC_ISR_MALFORMED,
|
||||
"Invalid field 'taker_pays.issuer', expected non-XRP issuer.");
|
||||
|
||||
std::optional<std::uint32_t> expiration;
|
||||
if (context.params.isMember(jss::expiration))
|
||||
{
|
||||
if (!context.params[jss::expiration].isString())
|
||||
return RPC::expected_field_error(jss::expiration, "string");
|
||||
|
||||
expiration = context.params[jss::expiration].asInt();
|
||||
if (!expiration)
|
||||
return RPC::invalid_field_error(jss::expiration);
|
||||
}
|
||||
|
||||
unsigned int limit;
|
||||
if (auto err = readLimitField(limit, RPC::Tuning::bookOffers, context))
|
||||
return *err;
|
||||
|
||||
bool const bProof(context.params.isMember(jss::proof));
|
||||
|
||||
Json::Value const jvMarker(
|
||||
context.params.isMember(jss::marker) ? context.params[jss::marker]
|
||||
: Json::Value(Json::nullValue));
|
||||
|
||||
context.netOps.getOptionBookPage(
|
||||
lpLedger,
|
||||
STAmount(Issue(pay_currency, pay_issuer), pay_value ? *pay_value : 0),
|
||||
expiration ? *expiration : 0,
|
||||
limit,
|
||||
jvMarker,
|
||||
jvResult);
|
||||
|
||||
context.loadType = Resource::feeMediumBurdenRPC;
|
||||
|
||||
return jvResult;
|
||||
}
|
||||
|
||||
} // namespace ripple
|
||||
@@ -118,7 +118,6 @@ Handler const handlerArray[]{
|
||||
{"nft_sell_offers", byRef(&doNFTSellOffers), Role::USER, NO_CONDITION},
|
||||
{"node_to_shard", byRef(&doNodeToShard), Role::ADMIN, NO_CONDITION},
|
||||
{"noripple_check", byRef(&doNoRippleCheck), Role::USER, NO_CONDITION},
|
||||
{"option_book_offers", byRef(&doOptionBookOffers), Role::USER, NO_CONDITION},
|
||||
{"owner_info", byRef(&doOwnerInfo), Role::USER, NEEDS_CURRENT_LEDGER},
|
||||
{"peers", byRef(&doPeers), Role::ADMIN, NO_CONDITION},
|
||||
{"path_find", byRef(&doPathFind), Role::USER, NEEDS_CURRENT_LEDGER},
|
||||
|
||||
@@ -1067,7 +1067,7 @@ chooseLedgerEntryType(Json::Value const& params)
|
||||
std::pair<RPC::Status, LedgerEntryType> result{RPC::Status::OK, ltANY};
|
||||
if (params.isMember(jss::type))
|
||||
{
|
||||
static constexpr std::array<std::pair<char const*, LedgerEntryType>, 23>
|
||||
static constexpr std::array<std::pair<char const*, LedgerEntryType>, 22>
|
||||
types{
|
||||
{{jss::account, ltACCOUNT_ROOT},
|
||||
{jss::amendments, ltAMENDMENTS},
|
||||
@@ -1083,7 +1083,6 @@ chooseLedgerEntryType(Json::Value const& params)
|
||||
{jss::hashes, ltLEDGER_HASHES},
|
||||
{jss::import_vlseq, ltIMPORT_VLSEQ},
|
||||
{jss::offer, ltOFFER},
|
||||
{jss::option, ltOPTION},
|
||||
{jss::payment_channel, ltPAYCHAN},
|
||||
{jss::uri_token, ltURI_TOKEN},
|
||||
{jss::signer_list, ltSIGNER_LIST},
|
||||
|
||||
@@ -15,8 +15,8 @@
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#include <ripple/app/tx/impl/XahauGenesis.h>
|
||||
#include <ripple/protocol/Feature.h>
|
||||
#include <ripple/protocol/jss.h>
|
||||
#include <optional>
|
||||
#include <test/jtx.h>
|
||||
|
||||
@@ -94,7 +94,7 @@ struct GenesisMint_test : public beast::unit_test::suite
|
||||
using namespace jtx;
|
||||
using namespace std::literals::chrono_literals;
|
||||
|
||||
Env env{*this, envconfig(), features, nullptr};
|
||||
Env env{*this, envconfig(), features};
|
||||
auto const alice = Account("alice");
|
||||
auto const bob = Account("bob");
|
||||
auto const invoker = Account("invoker");
|
||||
@@ -133,11 +133,7 @@ struct GenesisMint_test : public beast::unit_test::suite
|
||||
using namespace jtx;
|
||||
using namespace std::literals::chrono_literals;
|
||||
|
||||
Env env{*this, envconfig(), features, nullptr};
|
||||
// Env env{*this, envconfig(), features, nullptr,
|
||||
// // beast::severities::kWarning
|
||||
// beast::severities::kTrace
|
||||
// };
|
||||
Env env{*this, envconfig(), features};
|
||||
auto const alice = Account("alice");
|
||||
auto const bob = Account("bob");
|
||||
auto const invoker = Account("invoker");
|
||||
@@ -639,7 +635,7 @@ struct GenesisMint_test : public beast::unit_test::suite
|
||||
using namespace jtx;
|
||||
using namespace std::literals::chrono_literals;
|
||||
|
||||
Env env{*this, envconfig(), features, nullptr};
|
||||
Env env{*this, envconfig(), features};
|
||||
auto const alice = Account("alice");
|
||||
auto const bob = Account("bob");
|
||||
env.fund(XRP(10000), alice, bob);
|
||||
@@ -661,7 +657,7 @@ struct GenesisMint_test : public beast::unit_test::suite
|
||||
using namespace jtx;
|
||||
using namespace std::literals::chrono_literals;
|
||||
|
||||
Env env{*this, envconfig(), features, nullptr};
|
||||
Env env{*this, envconfig(), features};
|
||||
auto const alice = Account("alice");
|
||||
auto const bob = Account("bob");
|
||||
env.fund(XRP(10000), alice, bob);
|
||||
|
||||
@@ -1,621 +0,0 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2016 Ripple Labs Inc.
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#include <ripple/protocol/Feature.h>
|
||||
#include <ripple/protocol/Indexes.h>
|
||||
#include <ripple/protocol/TxFlags.h>
|
||||
#include <ripple/protocol/jss.h>
|
||||
#include <test/jtx.h>
|
||||
|
||||
namespace ripple {
|
||||
namespace test {
|
||||
|
||||
struct Option_test : public beast::unit_test::suite
|
||||
{
|
||||
// testDebug("PRE", env, { alice, bob }, {});
|
||||
void
|
||||
testDebug(
|
||||
std::string const& testNumber,
|
||||
jtx::Env const& env,
|
||||
std::vector<jtx::Account> const& accounts,
|
||||
std::vector<jtx::IOU> const& ious)
|
||||
{
|
||||
std::cout << "DEBUG: " << testNumber << "\n";
|
||||
for (std::size_t a = 0; a < accounts.size(); ++a)
|
||||
{
|
||||
auto const bal = env.balance(accounts[a]);
|
||||
std::cout << "account: " << accounts[a].human() << "BAL: " << bal
|
||||
<< "\n";
|
||||
for (std::size_t i = 0; i < ious.size(); ++i)
|
||||
{
|
||||
auto const iouBal = env.balance(accounts[a], ious[i]);
|
||||
std::cout << "account: " << accounts[a].human()
|
||||
<< "IOU: " << iouBal << "\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static STAmount
|
||||
lockedValue(
|
||||
jtx::Env const& env,
|
||||
jtx::Account const& account,
|
||||
std::uint32_t const& seq)
|
||||
{
|
||||
auto const sle = env.le(keylet::optionOffer(account, seq));
|
||||
if (sle->isFieldPresent(sfLockedBalance))
|
||||
return (*sle)[sfLockedBalance];
|
||||
return STAmount(0);
|
||||
}
|
||||
|
||||
Json::Value
|
||||
optionlist(
|
||||
jtx::Account const& account,
|
||||
std::uint32_t expiration,
|
||||
STAmount const& strikePrice,
|
||||
STAmount const& amount)
|
||||
{
|
||||
using namespace jtx;
|
||||
Json::Value jv;
|
||||
jv[jss::TransactionType] = jss::OptionList;
|
||||
jv[jss::Account] = account.human();
|
||||
jv[sfStrikePrice.jsonName] = strikePrice.getJson(JsonOptions::none);
|
||||
jv[sfIssuer.jsonName] = to_string(amount.getIssuer());
|
||||
jv[sfCurrency.jsonName] = to_string(amount.getCurrency());
|
||||
jv[sfExpiration.jsonName] = expiration;
|
||||
return jv;
|
||||
}
|
||||
|
||||
Json::Value
|
||||
optioncreate(
|
||||
jtx::Account const& account,
|
||||
uint256 const& optionId,
|
||||
uint32_t const& quantity,
|
||||
STAmount const& premium)
|
||||
{
|
||||
using namespace jtx;
|
||||
Json::Value jv;
|
||||
jv[jss::TransactionType] = jss::OptionCreate;
|
||||
jv[jss::Account] = account.human();
|
||||
jv[sfOptionID.jsonName] = to_string(optionId);
|
||||
jv[jss::Amount] = premium.getJson(JsonOptions::none);
|
||||
jv[sfQuantity.jsonName] = quantity;
|
||||
return jv;
|
||||
}
|
||||
|
||||
Json::Value
|
||||
optionexecute(
|
||||
jtx::Account const& account,
|
||||
uint256 const& optionId,
|
||||
uint256 const& offerId)
|
||||
{
|
||||
using namespace jtx;
|
||||
Json::Value jv;
|
||||
jv[jss::TransactionType] = jss::OptionExercise;
|
||||
jv[jss::Account] = account.human();
|
||||
jv[sfOptionID.jsonName] = to_string(optionId);
|
||||
jv[sfSwapID.jsonName] = to_string(offerId);
|
||||
;
|
||||
return jv;
|
||||
}
|
||||
|
||||
static uint256
|
||||
getOptionIndex(
|
||||
AccountID const& issuer,
|
||||
Currency const& currency,
|
||||
std::uint64_t const& strike,
|
||||
std::uint32_t expiration)
|
||||
{
|
||||
return keylet::option(issuer, currency, strike, expiration).key;
|
||||
}
|
||||
|
||||
static uint256
|
||||
getOfferIndex(AccountID const& account, std::uint32_t sequence)
|
||||
{
|
||||
return keylet::optionOffer(account, sequence).key;
|
||||
}
|
||||
|
||||
static auto
|
||||
getOptionList(
|
||||
jtx::Env& env,
|
||||
AccountID const& issuer)
|
||||
{
|
||||
Json::Value jvbp;
|
||||
jvbp[jss::ledger_index] = "current";
|
||||
jvbp[jss::account] = to_string(issuer);
|
||||
jvbp[jss::type] = "option";
|
||||
return env.rpc("json", "account_objects", to_string(jvbp))[jss::result];
|
||||
}
|
||||
|
||||
static auto
|
||||
getOptionBookOffers(
|
||||
jtx::Env& env,
|
||||
STAmount const& strike_price,
|
||||
std::uint32_t expiration)
|
||||
{
|
||||
Json::Value jvbp;
|
||||
jvbp[jss::ledger_index] = "current";
|
||||
jvbp[jss::strike_price][jss::currency] = to_string(strike_price.issue().currency);
|
||||
jvbp[jss::strike_price][jss::issuer] = to_string(strike_price.issue().account);
|
||||
jvbp[jss::strike_price][jss::value] = to_string(strike_price.mantissa());
|
||||
jvbp[jss::expiration] = to_string(expiration);
|
||||
return env.rpc("json", "option_book_offers", to_string(jvbp))[jss::result];
|
||||
}
|
||||
|
||||
// void
|
||||
// testBookBuy(FeatureBitset features)
|
||||
// {
|
||||
// testcase("book buy");
|
||||
|
||||
// using namespace test::jtx;
|
||||
// using namespace std::literals;
|
||||
|
||||
// test::jtx::Env env{*this, network::makeNetworkConfig(21337)};
|
||||
|
||||
// auto const alice = Account("alice");
|
||||
// auto const bob = Account("bob");
|
||||
// auto const gw = Account("gw");
|
||||
// IOU const USD(gw["USD"]);
|
||||
|
||||
// env.fund(XRP(1000), gw, alice, bob);
|
||||
// env.close();
|
||||
// env.trust(USD(100000), alice, bob);
|
||||
// env.close();
|
||||
// env(pay(gw, alice, USD(10000)));
|
||||
// env(pay(gw, bob, USD(10000)));
|
||||
// env.close();
|
||||
|
||||
// // Alice offers to sell 100 XRP for 110 USD.
|
||||
// // Create an sell: TakerPays 100, TakerGets 110/USD
|
||||
// env(offer(alice, XRP(100), USD(110)), txflags(tfSell)); // <- Best
|
||||
// // Alice offers to sell 100 XRP for 100 USD.
|
||||
// // Create an sell: TakerPays 100, TakerGets 100/USD
|
||||
// env(offer(alice, XRP(100), USD(100)), txflags(tfSell));
|
||||
// // Alice offers to sell 100 XRP for 90 USD.
|
||||
// // Create an sell: TakerPays 100, TakerGets 90/USD
|
||||
// env(offer(alice, XRP(100), USD(90)), txflags(tfSell));
|
||||
// // Alice offers to sell 100 XRP for 80 USD.
|
||||
// // Create an sell: TakerPays 100, TakerGets 80/USD
|
||||
// env(offer(alice, XRP(100), USD(80)), txflags(tfSell));
|
||||
// // Alice offers to sell 100 XRP for 70 USD.
|
||||
// // Create an sell: TakerPays 100, TakerGets 70/USD
|
||||
// env(offer(alice, XRP(100), USD(70)), txflags(tfSell)); // <- Worst
|
||||
// env.close();
|
||||
|
||||
// // Bob offers to buy 110 USD for 100 XRP.
|
||||
// // env(offer(bob, USD(110), XRP(100))); // <- Best
|
||||
|
||||
// Book const book1{
|
||||
// xrpIssue(),
|
||||
// USD.issue(),
|
||||
// };
|
||||
|
||||
// const uint256 uBookBase1 = getBookBase(book1);
|
||||
// const uint256 uBookEnd1 = getQualityNext(uBookBase1);
|
||||
// auto view1 = env.closed();
|
||||
// auto key1 = view1->succ(uBookBase1, uBookEnd1);
|
||||
// if (key1)
|
||||
// {
|
||||
// auto sleOfferDir1 = view1->read(keylet::page(key1.value()));
|
||||
// uint256 offerIndex1;
|
||||
// unsigned int bookEntry1;
|
||||
// cdirFirst(
|
||||
// *view1,
|
||||
// sleOfferDir1->key(),
|
||||
// sleOfferDir1,
|
||||
// bookEntry1,
|
||||
// offerIndex1);
|
||||
// auto sleOffer1 = view1->read(keylet::offer(offerIndex1));
|
||||
// auto const dir1 =
|
||||
// to_string(sleOffer1->getFieldH256(sfBookDirectory));
|
||||
// auto const uTipIndex1 = sleOfferDir1->key();
|
||||
// STAmount dirRate1 = amountFromQuality(getQuality(uTipIndex1));
|
||||
// auto const rate1 = dirRate1 / 1'000'000;
|
||||
// std::cout << "dirRate1: " << dirRate1 << "\n";
|
||||
// std::cout << "rate1: " << rate1 << "\n";
|
||||
// std::cout << "rate1=: " << (100 / rate1) << "\n";
|
||||
// BEAST_EXPECT(100 / rate1 == 110);
|
||||
// }
|
||||
// }
|
||||
|
||||
// void
|
||||
// testBookSell(FeatureBitset features)
|
||||
// {
|
||||
// testcase("book sell");
|
||||
|
||||
// using namespace test::jtx;
|
||||
// using namespace std::literals;
|
||||
|
||||
// test::jtx::Env env{*this, network::makeNetworkConfig(21337)};
|
||||
|
||||
// auto const alice = Account("alice");
|
||||
// auto const bob = Account("bob");
|
||||
// auto const gw = Account("gw");
|
||||
// IOU const USD(gw["USD"]);
|
||||
|
||||
// env.fund(XRP(1000), gw, alice, bob);
|
||||
// env.close();
|
||||
// env.trust(USD(100000), alice, bob);
|
||||
// env.close();
|
||||
// env(pay(gw, alice, USD(10000)));
|
||||
// env(pay(gw, bob, USD(10000)));
|
||||
// env.close();
|
||||
|
||||
// // Bob offers to buy 70 XRP for 100 USD.
|
||||
// // Create an buy: TakerPays 100/USD, TakerGets 70
|
||||
// env(offer(bob, USD(100), XRP(70))); // <- Worst
|
||||
// // Bob offers to buy 80 XRP for 100 USD.
|
||||
// // Create an buy: TakerPays 100/USD, TakerGets 80
|
||||
// env(offer(bob, USD(100), XRP(80)));
|
||||
// // Bob offers to buy 90 XRP for 100 USD.
|
||||
// // Create an buy: TakerPays 100/USD, TakerGets 90
|
||||
// env(offer(bob, USD(100), XRP(90)));
|
||||
// // Bob offers to buy 100 XRP for 100 USD.
|
||||
// // Create an buy: TakerPays 100/USD, TakerGets 100
|
||||
// env(offer(bob, USD(100), XRP(100)));
|
||||
// // Bob offers to buy 110 XRP for 100 USD.
|
||||
// // Create an buy: TakerPays 100/USD, TakerGets 110
|
||||
// env(offer(bob, USD(100), XRP(110))); // <- Best
|
||||
// env.close();
|
||||
|
||||
// // Alice offers to sell 110 XRP for 100 USD.
|
||||
// // env(offer(alice, XRP(110), USD(100))); // <- Best
|
||||
|
||||
// Book const bookOpp{
|
||||
// USD.issue(),
|
||||
// xrpIssue(),
|
||||
// };
|
||||
|
||||
// const uint256 uBookBaseOpp = getBookBase(bookOpp);
|
||||
// const uint256 uBookEndOpp = getQualityNext(uBookBaseOpp);
|
||||
// auto view = env.closed();
|
||||
// auto key = view->succ(uBookBaseOpp, uBookEndOpp);
|
||||
// if (key)
|
||||
// {
|
||||
// auto sleOfferDir = view->read(keylet::page(key.value()));
|
||||
// uint256 offerIndex;
|
||||
// unsigned int bookEntry;
|
||||
// cdirFirst(
|
||||
// *view, sleOfferDir->key(), sleOfferDir, bookEntry, offerIndex);
|
||||
// auto sleOffer = view->read(keylet::offer(offerIndex));
|
||||
// auto const dir = to_string(sleOffer->getFieldH256(sfBookDirectory));
|
||||
// auto const uTipIndex = sleOfferDir->key();
|
||||
// STAmount dirRate = amountFromQuality(getQuality(uTipIndex));
|
||||
// auto const rate = dirRate * 1'000'000;
|
||||
// std::cout << "dirRate: " << dirRate << "\n";
|
||||
// std::cout << "rate: " << rate << "\n";
|
||||
// std::cout << "rate=: " << (100 / rate) << "\n";
|
||||
// BEAST_EXPECT(100 / rate == 110);
|
||||
// }
|
||||
// }
|
||||
|
||||
// void
|
||||
// testOptionBookBuy(FeatureBitset features)
|
||||
// {
|
||||
// testcase("option book buy");
|
||||
|
||||
// using namespace test::jtx;
|
||||
// using namespace std::literals;
|
||||
|
||||
// test::jtx::Env env{*this, network::makeNetworkConfig(21337)};
|
||||
|
||||
// auto const alice = Account("alice");
|
||||
// auto const bob = Account("bob");
|
||||
// auto const broker = Account("broker");
|
||||
// auto const gw = Account("gw");
|
||||
// IOU const USD(gw["USD"]);
|
||||
|
||||
// env.fund(XRP(1000), gw, alice, bob, broker);
|
||||
// env.close();
|
||||
// env.trust(USD(100000), alice, bob);
|
||||
// env.close();
|
||||
// env(pay(gw, alice, USD(10000)));
|
||||
// env(pay(gw, bob, USD(10000)));
|
||||
// env.close();
|
||||
|
||||
// AccountID const zeroAcct{AccountID{}};
|
||||
// auto const _exp = env.now() + 1s;
|
||||
// auto const expiration = _exp.time_since_epoch().count();
|
||||
// uint256 const optionId{getOptionIndex(zeroAcct, expiration)};
|
||||
// env(optionlist(alice, expiration, XRP(10), XRP(10)), ter(tesSUCCESS));
|
||||
// env.close();
|
||||
|
||||
// env(optioncreate(alice, optionId, 100, XRP(70)),
|
||||
// txflags(tfAction),
|
||||
// ter(tesSUCCESS));
|
||||
// env(optioncreate(alice, optionId, 100, XRP(80)),
|
||||
// txflags(tfAction),
|
||||
// ter(tesSUCCESS));
|
||||
// env(optioncreate(alice, optionId, 100, XRP(90)),
|
||||
// txflags(tfAction),
|
||||
// ter(tesSUCCESS));
|
||||
// env(optioncreate(alice, optionId, 100, XRP(100)),
|
||||
// txflags(tfAction),
|
||||
// ter(tesSUCCESS));
|
||||
// env(optioncreate(alice, optionId, 100, XRP(110)),
|
||||
// txflags(tfAction),
|
||||
// ter(tesSUCCESS));
|
||||
// env.close();
|
||||
|
||||
// STAmount strikePrice = XRP(10);
|
||||
// const uint256 uBookBaseOpp = getOptionBookBase(
|
||||
// strikePrice.getIssuer(),
|
||||
// strikePrice.getCurrency(),
|
||||
// strikePrice.mantissa(),
|
||||
// expiration);
|
||||
// std::cout << "BOOK BASE: " << uBookBaseOpp << "\n";
|
||||
// const uint256 uBookEndOpp = getOptionQualityNext(uBookBaseOpp);
|
||||
// std::cout << "BOOK BASE END: " << uBookEndOpp << "\n";
|
||||
// auto view = env.closed();
|
||||
// auto key = view->succ(uBookBaseOpp, uBookEndOpp);
|
||||
// if (key)
|
||||
// {
|
||||
// auto sleOfferDir = view->read(keylet::page(key.value()));
|
||||
// uint256 offerIndex;
|
||||
// unsigned int bookEntry;
|
||||
// cdirFirst(
|
||||
// *view, sleOfferDir->key(), sleOfferDir, bookEntry, offerIndex);
|
||||
// auto sleOffer = view->read(keylet::unchecked(offerIndex));
|
||||
// STAmount premium = sleOffer->getFieldAmount(sfAmount);
|
||||
// auto const dir = to_string(sleOffer->getFieldH256(sfBookDirectory));
|
||||
// std::cout << "dir: " << dir << "\n";
|
||||
// auto const uTipIndex = sleOfferDir->key();
|
||||
// auto const optionQuality = getOptionQuality(uTipIndex);
|
||||
// std::cout << "optionQuality: " << optionQuality << "\n";
|
||||
// STAmount dirRate = STAmount(premium.issue(), optionQuality);
|
||||
// std::cout << "dirRate: " << dirRate << "\n";
|
||||
// // BEAST_EXPECT(100 / rate == 110);
|
||||
// }
|
||||
// }
|
||||
|
||||
// void
|
||||
// testEnabled(FeatureBitset features)
|
||||
// {
|
||||
// using namespace test::jtx;
|
||||
// using namespace std::literals;
|
||||
// testcase("enabled");
|
||||
|
||||
// test::jtx::Env env{*this, network::makeNetworkConfig(21337), features};
|
||||
// // test::jtx::Env env{
|
||||
// // *this,
|
||||
// // network::makeNetworkConfig(21337),
|
||||
// // features,
|
||||
// // nullptr,
|
||||
// // beast::severities::kTrace};
|
||||
|
||||
// auto const feeDrops = env.current()->fees().base;
|
||||
|
||||
// auto const writer = Account("alice");
|
||||
// auto const buyer = Account("bob");
|
||||
// auto const gw = Account("gateway");
|
||||
// auto const USD = gw["USD"];
|
||||
|
||||
// env.fund(XRP(100000), writer, buyer, gw);
|
||||
// env.close();
|
||||
|
||||
// BEAST_EXPECT(0 == 0);
|
||||
// AccountID const zeroAcct{AccountID{}};
|
||||
|
||||
// auto const _exp = env.now() + 1s;
|
||||
// auto const expiration = _exp.time_since_epoch().count();
|
||||
// uint256 const optionId{getOptionIndex(zeroAcct, expiration)};
|
||||
|
||||
// auto preWriter = env.balance(writer);
|
||||
// auto preBuyer = env.balance(buyer);
|
||||
|
||||
// auto const strikePrice = 10;
|
||||
// env(optionlist(writer, expiration, XRP(strikePrice), XRP(strikePrice)),
|
||||
// ter(tesSUCCESS));
|
||||
// env.close();
|
||||
|
||||
// BEAST_EXPECT(env.balance(writer) == preWriter - feeDrops);
|
||||
|
||||
// // Call - Sell - Open
|
||||
// auto const premium = 1;
|
||||
// auto const quantity = 100;
|
||||
// auto const seq = env.seq(writer);
|
||||
// env(optioncreate(writer, optionId, quantity, XRP(premium)),
|
||||
// txflags(tfAction),
|
||||
// ter(tesSUCCESS));
|
||||
// env.close();
|
||||
|
||||
// BEAST_EXPECT(
|
||||
// env.balance(writer) ==
|
||||
// preWriter - (feeDrops * 2) - XRP(quantity));
|
||||
// BEAST_EXPECT(
|
||||
// lockedValue(env, writer, seq) == XRP(quantity));
|
||||
|
||||
// auto jrr = getOptionBookOffers(env, XRP(strikePrice), expiration);
|
||||
// std::cout << "RESULT: " << jrr << "\n";
|
||||
|
||||
// preWriter = env.balance(writer);
|
||||
// preBuyer = env.balance(buyer);
|
||||
|
||||
// // Call - Buy - Open
|
||||
// auto const seq1 = env.seq(buyer);
|
||||
// env(optioncreate(buyer, optionId, quantity, XRP(premium)),
|
||||
// ter(tesSUCCESS));
|
||||
// env.close();
|
||||
|
||||
// uint256 const offerId{getOfferIndex(buyer, seq1)};
|
||||
// BEAST_EXPECT(
|
||||
// env.balance(buyer) ==
|
||||
// preBuyer - feeDrops - XRP(quantity * premium));
|
||||
// BEAST_EXPECT(
|
||||
// env.balance(writer) ==
|
||||
// preWriter + XRP(quantity * premium));
|
||||
|
||||
// preWriter = env.balance(writer);
|
||||
// preBuyer = env.balance(buyer);
|
||||
|
||||
// auto jrr1 = getOptionBookOffers(env, XRP(strikePrice), expiration);
|
||||
// std::cout << "RESULT1: " << jrr1 << "\n";
|
||||
|
||||
// // Execute Option
|
||||
// env(optionexecute(buyer, optionId, offerId), ter(tesSUCCESS));
|
||||
// env.close();
|
||||
|
||||
// BEAST_EXPECT(
|
||||
// env.balance(buyer) ==
|
||||
// preBuyer - feeDrops - XRP(quantity * strikePrice) + XRP(quantity));
|
||||
// BEAST_EXPECT(
|
||||
// env.balance(writer) ==
|
||||
// preWriter + XRP(quantity * strikePrice));
|
||||
|
||||
// auto jrrList = getOptionList(env, zeroAcct);
|
||||
// std::cout << "RESULT LIST: " << jrrList << "\n";
|
||||
// auto jrr2 = getOptionBookOffers(env, XRP(strikePrice), expiration);
|
||||
// std::cout << "RESULT2: " << jrr2 << "\n";
|
||||
// }
|
||||
|
||||
void
|
||||
testIC(FeatureBitset features)
|
||||
{
|
||||
using namespace test::jtx;
|
||||
using namespace std::literals;
|
||||
testcase("ic");
|
||||
|
||||
// test::jtx::Env env{*this, network::makeNetworkConfig(21337), features};
|
||||
test::jtx::Env env{
|
||||
*this,
|
||||
network::makeNetworkConfig(21337),
|
||||
features,
|
||||
nullptr,
|
||||
beast::severities::kTrace};
|
||||
|
||||
auto const feeDrops = env.current()->fees().base;
|
||||
|
||||
auto const writer = Account("alice");
|
||||
auto const buyer = Account("bob");
|
||||
auto const gw = Account("gateway");
|
||||
auto const GME = gw["GME"];
|
||||
auto const USD = gw["USD"];
|
||||
|
||||
env.fund(XRP(100000), writer, buyer, gw);
|
||||
env.close();
|
||||
env.trust(USD(100000), writer, buyer);
|
||||
env.close();
|
||||
env(pay(gw, writer, USD(10000)));
|
||||
env(pay(gw, buyer, USD(10000)));
|
||||
env.close();
|
||||
env.trust(GME(100000), writer, buyer);
|
||||
env.close();
|
||||
env(pay(gw, writer, USD(10000)));
|
||||
env.close();
|
||||
|
||||
auto const _exp = env.now() + 1s;
|
||||
auto const expiration = _exp.time_since_epoch().count();
|
||||
uint256 const optionId{getOptionIndex(gw.id(), USD.currency, 20, expiration)};
|
||||
|
||||
auto preWriter = env.balance(writer);
|
||||
auto preWriterGME = env.balance(writer, GME.issue());
|
||||
auto preBuyer = env.balance(buyer);
|
||||
auto preBuyerGME = env.balance(buyer, GME.issue());
|
||||
|
||||
auto const strikePrice = 20;
|
||||
env(optionlist(writer, expiration, USD(strikePrice), GME(0)),
|
||||
ter(tesSUCCESS));
|
||||
env.close();
|
||||
|
||||
BEAST_EXPECT(env.balance(writer) == preWriter - feeDrops);
|
||||
|
||||
auto const strikePrice1 = 25;
|
||||
env(optionlist(writer, expiration, USD(strikePrice1), GME(0)),
|
||||
ter(tesSUCCESS));
|
||||
env.close();
|
||||
|
||||
// Call - Sell - Open
|
||||
auto const premium = 0.5;
|
||||
auto const quantity = 100;
|
||||
auto const seq = env.seq(writer);
|
||||
env(optioncreate(writer, optionId, quantity, XRP(premium)),
|
||||
txflags(tfAction),
|
||||
ter(tesSUCCESS));
|
||||
env.close();
|
||||
|
||||
BEAST_EXPECT(
|
||||
env.balance(writer) ==
|
||||
preWriter - (feeDrops * 2));
|
||||
BEAST_EXPECT(
|
||||
env.balance(writer, GME.issue()) == preWriterGME - GME(quantity));
|
||||
BEAST_EXPECT(
|
||||
lockedValue(env, writer, seq) == GME(quantity));
|
||||
|
||||
auto jrr = getOptionBookOffers(env, GME(strikePrice), expiration);
|
||||
std::cout << "RESULT: " << jrr << "\n";
|
||||
|
||||
preWriter = env.balance(writer);
|
||||
preWriterGME = env.balance(writer, GME.issue());
|
||||
preBuyer = env.balance(buyer);
|
||||
preBuyerGME = env.balance(buyer, GME.issue());
|
||||
|
||||
// // Call - Buy - Open
|
||||
// auto const seq1 = env.seq(buyer);
|
||||
// env(optioncreate(buyer, optionId, quantity, GME(premium)),
|
||||
// ter(tesSUCCESS));
|
||||
// env.close();
|
||||
|
||||
// uint256 const offerId{getOfferIndex(buyer, seq1)};
|
||||
// BEAST_EXPECT(
|
||||
// env.balance(buyer) ==
|
||||
// preBuyer - feeDrops - GME(quantity * premium));
|
||||
// BEAST_EXPECT(
|
||||
// env.balance(writer) ==
|
||||
// preWriter + GME(quantity * premium));
|
||||
|
||||
// preWriter = env.balance(writer);
|
||||
// preBuyer = env.balance(buyer);
|
||||
|
||||
// auto jrr1 = getOptionBookOffers(env, GME(strikePrice), expiration);
|
||||
// std::cout << "RESULT1: " << jrr1 << "\n";
|
||||
|
||||
// // Execute Option
|
||||
// env(optionexecute(buyer, optionId, offerId), ter(tesSUCCESS));
|
||||
// env.close();
|
||||
|
||||
// BEAST_EXPECT(
|
||||
// env.balance(buyer) ==
|
||||
// preBuyer - feeDrops - GME(quantity * strikePrice) + GME(quantity));
|
||||
// BEAST_EXPECT(
|
||||
// env.balance(writer) ==
|
||||
// preWriter + GME(quantity * strikePrice));
|
||||
|
||||
// auto jrrList = getOptionList(env, zeroAcct);
|
||||
// std::cout << "RESULT LIST: " << jrrList << "\n";
|
||||
// auto jrr2 = getOptionBookOffers(env, GME(strikePrice), expiration);
|
||||
// std::cout << "RESULT2: " << jrr2 << "\n";
|
||||
}
|
||||
|
||||
public:
|
||||
void
|
||||
run() override
|
||||
{
|
||||
using namespace test::jtx;
|
||||
auto const sa = supported_amendments();
|
||||
// testBookBuy(sa);
|
||||
// testBookSell(sa);
|
||||
// testOptionBookBuy(sa);
|
||||
// testEnabled(sa);
|
||||
testIC(sa);
|
||||
}
|
||||
};
|
||||
|
||||
BEAST_DEFINE_TESTSUITE(Option, app, ripple);
|
||||
|
||||
} // namespace test
|
||||
} // namespace ripple
|
||||
@@ -2132,7 +2132,6 @@ struct Remit_test : public beast::unit_test::suite
|
||||
auto const delta = USD(100);
|
||||
env(remit::remit(alice, bob), remit::amts({delta}));
|
||||
env.close();
|
||||
auto xferRate = transferRate(*env.current(), gw);
|
||||
auto const postAlice = env.balance(alice, USD.issue());
|
||||
BEAST_EXPECT(env.balance(bob, USD.issue()) == preBob + delta);
|
||||
BEAST_EXPECT(to_string(postAlice.value()) == tc.result);
|
||||
|
||||
103
src/test/app/SetHookDefinition_test.cpp
Normal file
103
src/test/app/SetHookDefinition_test.cpp
Normal file
@@ -0,0 +1,103 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2016 Ripple Labs Inc.
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#include <ripple/core/ConfigSections.h>
|
||||
#include <ripple/ledger/Directory.h>
|
||||
#include <ripple/protocol/Feature.h>
|
||||
#include <ripple/protocol/jss.h>
|
||||
#include <test/jtx.h>
|
||||
|
||||
namespace ripple {
|
||||
namespace test {
|
||||
struct SetHookDefinition_test : public beast::unit_test::suite
|
||||
{
|
||||
|
||||
Json::Value
|
||||
setDefinition(jtx::Account const& account, std::string const& hex)
|
||||
{
|
||||
using namespace jtx;
|
||||
Json::Value jv;
|
||||
jv[jss::TransactionType] = jss::SetHookDefinition;
|
||||
jv[jss::Account] = account.human();
|
||||
jv[jss::CreateCode] = hex;
|
||||
jv[sfHookNamespace.jsonName] = "0000000000000000000000000000000000000000000000000000000000000000";
|
||||
jv[sfHookOn.jsonName] = "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBFFFFFFFFFFFFFFFFFFBFFFFF";
|
||||
jv[sfHookApiVersion.jsonName] = 0;
|
||||
jv[sfFlags.jsonName] = hsfMUTALBE;
|
||||
return jv;
|
||||
}
|
||||
|
||||
void
|
||||
testEnabled()
|
||||
{
|
||||
using namespace test::jtx;
|
||||
testcase("Enabled");
|
||||
Account const alice = Account("alice");
|
||||
|
||||
for (bool const withFeature : {false, true})
|
||||
{
|
||||
// auto const amend = withFeature ? features : features - featureHooksUpdate2;
|
||||
Env env{*this};
|
||||
|
||||
env.fund(XRP(1000), alice);
|
||||
env.close();
|
||||
|
||||
// std::string const createCodeHex =
|
||||
// "0061736D01000000011C0460057F7F7F7F7F017E60037F7F7E017E60027F7F"
|
||||
// "017F60017F017E02250303656E76057472616365000003656E7608726F6C6C"
|
||||
// "6261636B000103656E76025F670002030201030503010002062B077F0141C0"
|
||||
// "88040B7F004180080B7F0041BE080B7F004180080B7F0041C088040B7F0041"
|
||||
// "000B7F0041010B07080104686F6F6B00030AC3800001BF800001017F230041"
|
||||
// "106B220124002001200036020C41940841154180084114410010001A41AA08"
|
||||
// "4114420A10011A41012200200010021A200141106A240042000B0B44010041"
|
||||
// "80080B3D526F6C6C6261636B2E633A2043616C6C65642E0022526F6C6C6261"
|
||||
// "636B2E633A2043616C6C65642E2200526F6C6C6261636B3A20526F6C6C6261"
|
||||
// "636B21";
|
||||
|
||||
// strHex(wasmBytes)
|
||||
// auto const txResult = withFeature ? ter(tesSUCCESS) : ter(temDISABLED);
|
||||
// env(setDefinition(alice, createCodeHex), fee(10), txResult);
|
||||
// env.close();
|
||||
|
||||
// Json::Value jvParams;
|
||||
// jvParams[jss::index] = "ledgerHash";
|
||||
// Json::Value const jrr = env.rpc("json", "ledger_entry", to_string(jvParams))[jss::result];
|
||||
}
|
||||
}
|
||||
|
||||
// void
|
||||
// testWithFeats(FeatureBitset features)
|
||||
// {
|
||||
// testEnabled(features);
|
||||
// }
|
||||
|
||||
public:
|
||||
void
|
||||
run() override
|
||||
{
|
||||
using namespace test::jtx;
|
||||
// auto const sa = supported_amendments();
|
||||
// testWithFeats(sa);
|
||||
testEnabled();
|
||||
}
|
||||
};
|
||||
|
||||
BEAST_DEFINE_TESTSUITE(SetHookDefinition, app, ripple);
|
||||
} // namespace test
|
||||
} // namespace ripple
|
||||
@@ -18,6 +18,7 @@
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#include <ripple/app/hook/Enum.h>
|
||||
#include <ripple/app/misc/HashRouter.h>
|
||||
#include <ripple/app/misc/TxQ.h>
|
||||
#include <ripple/app/tx/apply.h>
|
||||
@@ -31,6 +32,13 @@
|
||||
namespace ripple {
|
||||
namespace test {
|
||||
|
||||
#define BEAST_REQUIRE(x) \
|
||||
{ \
|
||||
BEAST_EXPECT(!!(x)); \
|
||||
if (!(x)) \
|
||||
return; \
|
||||
}
|
||||
|
||||
struct SetHookTSH_test : public beast::unit_test::suite
|
||||
{
|
||||
private:
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#include <ripple/protocol/jss.h>
|
||||
#include <test/jtx/Env.h>
|
||||
#include <test/jtx/acctdelete.h>
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#include <ripple/basics/StringUtilities.h>
|
||||
#include <ripple/json/json_reader.h>
|
||||
#include <ripple/json/json_writer.h>
|
||||
#include <ripple/protocol/Feature.h>
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include <ripple/json/json_value.h>
|
||||
#include <ripple/protocol/STAmount.h>
|
||||
#include <test/jtx/Account.h>
|
||||
#include <test/jtx/Env.h>
|
||||
|
||||
namespace ripple {
|
||||
namespace test {
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include <ripple/beast/unit_test.h>
|
||||
#include <ripple/protocol/ErrorCodes.h>
|
||||
#include <ripple/protocol/jss.h>
|
||||
#include <test/app/Import_json.h>
|
||||
#include <test/jtx.h>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
Reference in New Issue
Block a user