Skip to content

Commit

Permalink
fix CanTransfer (#28)
Browse files Browse the repository at this point in the history
* fix CanTransfer

* clang
  • Loading branch information
shawnxie999 authored May 8, 2024
1 parent bd8e0f5 commit aa8521a
Show file tree
Hide file tree
Showing 4 changed files with 79 additions and 6 deletions.
5 changes: 5 additions & 0 deletions src/ripple/app/tx/impl/Payment.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -453,6 +453,11 @@ Payment::doApply()
ter != tesSUCCESS)
return ter;

if (auto const ter = canTransfer(
view(), saDstAmount.mptIssue(), account_, uDstAccountID);
ter != tesSUCCESS)
return ter;

auto const& mpt = saDstAmount.mptIssue();
auto const& issuer = mpt.account();
// If globally/individually locked then
Expand Down
11 changes: 11 additions & 0 deletions src/ripple/ledger/View.h
Original file line number Diff line number Diff line change
Expand Up @@ -508,6 +508,17 @@ requireAuth(
MPTIssue const& mpt,
AccountID const& account);

/** Check if the destination account is allowed
* to receive MPT. Return tecNO_AUTH if it doesn't
* and tesSUCCESS otherwise.
*/
[[nodiscard]] TER
canTransfer(
ReadView const& view,
MPTIssue const& mpt,
AccountID const& from,
AccountID const& to);

/** Deleter function prototype. Returns the status of the entry deletion
* (if should not be skipped) and if the entry should be skipped. The status
* is always tesSUCCESS if the entry should be skipped.
Expand Down
17 changes: 17 additions & 0 deletions src/ripple/ledger/impl/View.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1698,6 +1698,23 @@ requireAuth(ReadView const& view, MPTIssue const& mpt, AccountID const& account)
return tesSUCCESS;
}

TER
canTransfer(
ReadView const& view,
MPTIssue const& mpt,
AccountID const& from,
AccountID const& to)
{
auto const mptID = keylet::mptIssuance(mpt.mpt());
if (auto const sle = view.read(mptID);
sle && !(sle->getFieldU32(sfFlags) & lsfMPTCanTransfer))
{
if (from != (*sle)[sfIssuer] && to != (*sle)[sfIssuer])
return TER{tecNO_AUTH};
}
return tesSUCCESS;
}

TER
cleanupOnAccountDelete(
ApplyView& view,
Expand Down
52 changes: 46 additions & 6 deletions src/test/app/MPToken_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -619,7 +619,8 @@ class MPToken_test : public beast::unit_test::suite

MPTTester mptAlice(env, alice, {.holders = {&bob, &carol}});

mptAlice.create({.ownerCount = 1, .holderCount = 0});
mptAlice.create(
{.ownerCount = 1, .holderCount = 0, .flags = tfMPTCanTransfer});

// env(mpt::authorize(alice, id.key, std::nullopt));
// env.close();
Expand All @@ -646,7 +647,9 @@ class MPToken_test : public beast::unit_test::suite
MPTTester mptAlice(env, alice, {.holders = {&bob}});

mptAlice.create(
{.ownerCount = 1, .holderCount = 0, .flags = tfMPTRequireAuth});
{.ownerCount = 1,
.holderCount = 0,
.flags = tfMPTRequireAuth | tfMPTCanTransfer});

mptAlice.authorize({.account = &bob});

Expand All @@ -661,7 +664,9 @@ class MPToken_test : public beast::unit_test::suite
MPTTester mptAlice(env, alice, {.holders = {&bob}});

mptAlice.create(
{.ownerCount = 1, .holderCount = 0, .flags = tfMPTRequireAuth});
{.ownerCount = 1,
.holderCount = 0,
.flags = tfMPTRequireAuth | tfMPTCanTransfer});

// bob creates an empty MPToken
mptAlice.authorize({.account = &bob});
Expand All @@ -687,7 +692,7 @@ class MPToken_test : public beast::unit_test::suite

MPTTester mptAlice(env, alice, {.holders = {&bob, &carol}});

mptAlice.create({.ownerCount = 1});
mptAlice.create({.ownerCount = 1, .flags = tfMPTCanTransfer});

mptAlice.authorize({.account = &bob});
mptAlice.authorize({.account = &carol});
Expand All @@ -707,7 +712,8 @@ class MPToken_test : public beast::unit_test::suite

MPTTester mptAlice(env, alice, {.holders = {&bob, &carol}});

mptAlice.create({.ownerCount = 1, .flags = tfMPTCanLock});
mptAlice.create(
{.ownerCount = 1, .flags = tfMPTCanLock | tfMPTCanTransfer});

mptAlice.authorize({.account = &bob});
mptAlice.authorize({.account = &carol});
Expand Down Expand Up @@ -745,7 +751,11 @@ class MPToken_test : public beast::unit_test::suite

MPTTester mptAlice(env, alice, {.holders = {&bob}});

mptAlice.create({.maxAmt = 100, .ownerCount = 1, .holderCount = 0});
mptAlice.create(
{.maxAmt = 100,
.ownerCount = 1,
.holderCount = 0,
.flags = tfMPTCanTransfer});

mptAlice.authorize({.account = &bob});

Expand Down Expand Up @@ -806,6 +816,36 @@ class MPToken_test : public beast::unit_test::suite
// Payment between the holders. The sender pays 10% transfer fee.
mptAlice.pay(bob, carol, 100);
}

// Test that non-issuer cannot send to each other if MPTCanTransfer
// isn't set
{
Env env(*this, features);
Account const alice{"alice"};
Account const bob{"bob"};
Account const cindy{"cindy"};

MPTTester mptAlice(env, alice, {.holders = {&bob, &cindy}});

// alice creates issuance without MPTCanTransfer
mptAlice.create({.ownerCount = 1, .holderCount = 0});

// bob creates a MPToken
mptAlice.authorize({.account = &bob});

// cindy creates a MPToken
mptAlice.authorize({.account = &cindy});

// alice pays bob 100 tokens
mptAlice.pay(alice, bob, 100);

// bob tries to send cindy 10 tokens, but fails because canTransfer
// is off
mptAlice.pay(bob, cindy, 10, tecNO_AUTH);

// bob can send back to alice(issuer) just fine
mptAlice.pay(bob, alice, 10);
}
}

void
Expand Down

0 comments on commit aa8521a

Please sign in to comment.