#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace xrpl::test::jtx { // use this for creating a bridge for a transaction json::Value bridge( Account const& lockingChainDoor, Issue const& lockingChainIssue, Account const& issuingChainDoor, Issue const& issuingChainIssue) { json::Value jv; jv[jss::LockingChainDoor] = lockingChainDoor.human(); jv[jss::LockingChainIssue] = toJson(lockingChainIssue); jv[jss::IssuingChainDoor] = issuingChainDoor.human(); jv[jss::IssuingChainIssue] = toJson(issuingChainIssue); return jv; } // use this for creating a bridge for a rpc query json::Value bridgeRpc( Account const& lockingChainDoor, Issue const& lockingChainIssue, Account const& issuingChainDoor, Issue const& issuingChainIssue) { json::Value jv; jv[jss::LockingChainDoor] = lockingChainDoor.human(); jv[jss::LockingChainIssue] = toJson(lockingChainIssue); jv[jss::IssuingChainDoor] = issuingChainDoor.human(); jv[jss::IssuingChainIssue] = toJson(issuingChainIssue); return jv; } json::Value bridgeCreate( Account const& acc, json::Value const& bridge, STAmount const& reward, std::optional const& minAccountCreate) { json::Value jv; jv[jss::Account] = acc.human(); jv[sfXChainBridge.getJsonName()] = bridge; jv[sfSignatureReward.getJsonName()] = reward.getJson(JsonOptions::Values::None); if (minAccountCreate) { jv[sfMinAccountCreateAmount.getJsonName()] = minAccountCreate->getJson(JsonOptions::Values::None); } jv[jss::TransactionType] = jss::XChainCreateBridge; return jv; } json::Value bridgeModify( Account const& acc, json::Value const& bridge, std::optional const& reward, std::optional const& minAccountCreate) { json::Value jv; jv[jss::Account] = acc.human(); jv[sfXChainBridge.getJsonName()] = bridge; if (reward) jv[sfSignatureReward.getJsonName()] = reward->getJson(JsonOptions::Values::None); if (minAccountCreate) { jv[sfMinAccountCreateAmount.getJsonName()] = minAccountCreate->getJson(JsonOptions::Values::None); } jv[jss::TransactionType] = jss::XChainModifyBridge; return jv; } json::Value xchainCreateClaimId( Account const& acc, json::Value const& bridge, STAmount const& reward, Account const& otherChainSource) { json::Value jv; jv[jss::Account] = acc.human(); jv[sfXChainBridge.getJsonName()] = bridge; jv[sfSignatureReward.getJsonName()] = reward.getJson(JsonOptions::Values::None); jv[sfOtherChainSource.getJsonName()] = otherChainSource.human(); jv[jss::TransactionType] = jss::XChainCreateClaimID; return jv; } json::Value xchainCommit( Account const& acc, json::Value const& bridge, std::uint32_t claimID, AnyAmount const& amt, std::optional const& dst) { json::Value jv; jv[jss::Account] = acc.human(); jv[sfXChainBridge.getJsonName()] = bridge; jv[sfXChainClaimID.getJsonName()] = claimID; jv[jss::Amount] = amt.value.getJson(JsonOptions::Values::None); if (dst) jv[sfOtherChainDestination.getJsonName()] = dst->human(); jv[jss::TransactionType] = jss::XChainCommit; return jv; } json::Value xchainClaim( Account const& acc, json::Value const& bridge, std::uint32_t claimID, AnyAmount const& amt, Account const& dst) { json::Value jv; jv[sfAccount.getJsonName()] = acc.human(); jv[sfXChainBridge.getJsonName()] = bridge; jv[sfXChainClaimID.getJsonName()] = claimID; jv[sfDestination.getJsonName()] = dst.human(); jv[sfAmount.getJsonName()] = amt.value.getJson(JsonOptions::Values::None); jv[jss::TransactionType] = jss::XChainClaim; return jv; } json::Value sidechainXchainAccountCreate( Account const& acc, json::Value const& bridge, Account const& dst, AnyAmount const& amt, AnyAmount const& reward) { json::Value jv; jv[sfAccount.getJsonName()] = acc.human(); jv[sfXChainBridge.getJsonName()] = bridge; jv[sfDestination.getJsonName()] = dst.human(); jv[sfAmount.getJsonName()] = amt.value.getJson(JsonOptions::Values::None); jv[sfSignatureReward.getJsonName()] = reward.value.getJson(JsonOptions::Values::None); jv[jss::TransactionType] = jss::XChainAccountCreateCommit; return jv; } json::Value claimAttestation( jtx::Account const& submittingAccount, json::Value const& jvBridge, jtx::Account const& sendingAccount, jtx::AnyAmount const& sendingAmount, jtx::Account const& rewardAccount, bool wasLockingChainSend, std::uint64_t claimID, std::optional const& dst, jtx::Signer const& signer) { STXChainBridge const stBridge(jvBridge); auto const& pk = signer.account.pk(); auto const& sk = signer.account.sk(); auto const sig = signClaimAttestation( pk, sk, stBridge, sendingAccount, sendingAmount.value, rewardAccount, wasLockingChainSend, claimID, dst); json::Value result; result[sfAccount.getJsonName()] = submittingAccount.human(); result[sfXChainBridge.getJsonName()] = jvBridge; result[sfAttestationSignerAccount.getJsonName()] = signer.account.human(); result[sfPublicKey.getJsonName()] = strHex(pk.slice()); result[sfSignature.getJsonName()] = strHex(sig); result[sfOtherChainSource.getJsonName()] = toBase58(sendingAccount); result[sfAmount.getJsonName()] = sendingAmount.value.getJson(JsonOptions::Values::None); result[sfAttestationRewardAccount.getJsonName()] = toBase58(rewardAccount); result[sfWasLockingChainSend.getJsonName()] = wasLockingChainSend ? 1 : 0; result[sfXChainClaimID.getJsonName()] = STUInt64{claimID}.getJson(JsonOptions::Values::None); if (dst) result[sfDestination.getJsonName()] = toBase58(*dst); result[jss::TransactionType] = jss::XChainAddClaimAttestation; return result; } json::Value createAccountAttestation( jtx::Account const& submittingAccount, json::Value const& jvBridge, jtx::Account const& sendingAccount, jtx::AnyAmount const& sendingAmount, jtx::AnyAmount const& rewardAmount, jtx::Account const& rewardAccount, bool wasLockingChainSend, std::uint64_t createCount, jtx::Account const& dst, jtx::Signer const& signer) { STXChainBridge const stBridge(jvBridge); auto const& pk = signer.account.pk(); auto const& sk = signer.account.sk(); auto const sig = jtx::signCreateAccountAttestation( pk, sk, stBridge, sendingAccount, sendingAmount.value, rewardAmount.value, rewardAccount, wasLockingChainSend, createCount, dst); json::Value result; result[sfAccount.getJsonName()] = submittingAccount.human(); result[sfXChainBridge.getJsonName()] = jvBridge; result[sfAttestationSignerAccount.getJsonName()] = signer.account.human(); result[sfPublicKey.getJsonName()] = strHex(pk.slice()); result[sfSignature.getJsonName()] = strHex(sig); result[sfOtherChainSource.getJsonName()] = toBase58(sendingAccount); result[sfAmount.getJsonName()] = sendingAmount.value.getJson(JsonOptions::Values::None); result[sfAttestationRewardAccount.getJsonName()] = toBase58(rewardAccount); result[sfWasLockingChainSend.getJsonName()] = wasLockingChainSend ? 1 : 0; result[sfXChainAccountCreateCount.getJsonName()] = STUInt64{createCount}.getJson(JsonOptions::Values::None); result[sfDestination.getJsonName()] = toBase58(dst); result[sfSignatureReward.getJsonName()] = rewardAmount.value.getJson(JsonOptions::Values::None); result[jss::TransactionType] = jss::XChainAddAccountCreateAttestation; return result; } JValueVec claimAttestations( jtx::Account const& submittingAccount, json::Value const& jvBridge, jtx::Account const& sendingAccount, jtx::AnyAmount const& sendingAmount, std::vector const& rewardAccounts, bool wasLockingChainSend, std::uint64_t claimID, std::optional const& dst, std::vector const& signers, std::size_t const numAtts, std::size_t const fromIdx) { assert(fromIdx + numAtts <= rewardAccounts.size()); assert(fromIdx + numAtts <= signers.size()); JValueVec vec; vec.reserve(numAtts); for (auto i = fromIdx; i < fromIdx + numAtts; ++i) { vec.emplace_back(claimAttestation( submittingAccount, jvBridge, sendingAccount, sendingAmount, rewardAccounts[i], wasLockingChainSend, claimID, dst, signers[i])); } return vec; } JValueVec createAccountAttestations( jtx::Account const& submittingAccount, json::Value const& jvBridge, jtx::Account const& sendingAccount, jtx::AnyAmount const& sendingAmount, jtx::AnyAmount const& rewardAmount, std::vector const& rewardAccounts, bool wasLockingChainSend, std::uint64_t createCount, jtx::Account const& dst, std::vector const& signers, std::size_t const numAtts, std::size_t const fromIdx) { assert(fromIdx + numAtts <= rewardAccounts.size()); assert(fromIdx + numAtts <= signers.size()); JValueVec vec; vec.reserve(numAtts); for (auto i = fromIdx; i < fromIdx + numAtts; ++i) { vec.emplace_back(createAccountAttestation( submittingAccount, jvBridge, sendingAccount, sendingAmount, rewardAmount, rewardAccounts[i], wasLockingChainSend, createCount, dst, signers[i])); } return vec; } XChainBridgeObjects::XChainBridgeObjects() : mcDoor("mcDoor") , mcAlice("mcAlice") , mcBob("mcBob") , mcCarol("mcCarol") , mcGw("mcGw") , scDoor("scDoor") , scAlice("scAlice") , scBob("scBob") , scCarol("scCarol") , scGw("scGw") , scAttester("scAttester") , scReward("scReward") , mcuDoor("mcuDoor") , mcuAlice("mcuAlice") , mcuBob("mcuBob") , mcuCarol("mcuCarol") , mcuGw("mcuGw") , scuDoor("scuDoor") , scuAlice("scuAlice") , scuBob("scuBob") , scuCarol("scuCarol") , scuGw("scuGw") , mcUSD(mcGw["USD"]) , scUSD(scGw["USD"]) , jvXRPBridgeRPC(bridgeRpc(mcDoor, xrpIssue(), Account::kMaster, xrpIssue())) , jvb(bridge(mcDoor, xrpIssue(), Account::kMaster, xrpIssue())) , jvub(bridge(mcuDoor, xrpIssue(), Account::kMaster, xrpIssue())) , features(testableAmendments() | FeatureBitset{featureXChainBridge}) , signers([] { static constexpr int kNumSigners = kUtXchainDefaultNumSigners; std::vector result; result.reserve(kNumSigners); for (int i = 0; i < kNumSigners; ++i) { using namespace std::literals; auto const a = Account( "signer_"s + std::to_string(i), (i % 2) ? KeyType::Ed25519 : KeyType::Secp256k1); result.emplace_back(a); } return result; }()) , altSigners([] { static constexpr int kNumSigners = kUtXchainDefaultNumSigners; std::vector result; result.reserve(kNumSigners); for (int i = 0; i < kNumSigners; ++i) { using namespace std::literals; auto const a = Account( "alt_signer_"s + std::to_string(i), (i % 2) ? KeyType::Ed25519 : KeyType::Secp256k1); result.emplace_back(a); } return result; }()) , payee([&] { std::vector r; r.reserve(signers.size()); for (int i = 0, e = signers.size(); i != e; ++i) { r.push_back(scReward); } return r; }()) , payees([&] { std::vector r; r.reserve(signers.size()); for (int i = 0, e = signers.size(); i != e; ++i) { using namespace std::literals; auto const a = Account("reward_"s + std::to_string(i)); r.push_back(a); } return r; }()) , reward(XRP(1)) , splitRewardQuorum(divide(reward, STAmount(kUtXchainDefaultQuorum), reward.get())) , splitRewardEveryone(divide(reward, STAmount(kUtXchainDefaultNumSigners), reward.get())) , tinyReward(drops(37)) , tinyRewardSplit( (divide(tinyReward, STAmount(kUtXchainDefaultQuorum), tinyReward.get()))) , tinyRewardRemainder( tinyReward - multiply(tinyRewardSplit, STAmount(kUtXchainDefaultQuorum), tinyReward.get())) , oneXrp(XRP(1)) , xrpDust(divide(oneXrp, STAmount(10000), oneXrp.get())) { } void XChainBridgeObjects::createMcBridgeObjects(Env& mcEnv) { STAmount const xrpFunds{XRP(10000)}; mcEnv.fund(xrpFunds, mcDoor, mcAlice, mcBob, mcCarol, mcGw); // Signer's list must match the attestation signers mcEnv(jtx::signers(mcDoor, signers.size(), signers)); // create XRP bridges in both direction auto const reward = XRP(1); STAmount const minCreate = XRP(20); mcEnv(bridgeCreate(mcDoor, jvb, reward, minCreate)); mcEnv.close(); } void XChainBridgeObjects::createScBridgeObjects(Env& scEnv) { STAmount const xrpFunds{XRP(10000)}; scEnv.fund(xrpFunds, scDoor, scAlice, scBob, scCarol, scGw, scAttester, scReward); // Signer's list must match the attestation signers scEnv(jtx::signers(Account::kMaster, signers.size(), signers)); // create XRP bridges in both direction auto const reward = XRP(1); STAmount const minCreate = XRP(20); scEnv(bridgeCreate(Account::kMaster, jvb, reward, minCreate)); scEnv.close(); } void XChainBridgeObjects::createBridgeObjects(Env& mcEnv, Env& scEnv) { createMcBridgeObjects(mcEnv); createScBridgeObjects(scEnv); } } // namespace xrpl::test::jtx