This commit is contained in:
parent
5d3a3adb86
commit
1a38cfe5d7
7 changed files with 169 additions and 17 deletions
|
|
@ -630,6 +630,13 @@ public:
|
|||
const bool decisive = now >= deadline;
|
||||
|
||||
bool anyUnknown = false;
|
||||
// Money visible at "latest" while the settlement tag still reads
|
||||
// short. Display-only, and deliberately held to a LOWER standard
|
||||
// than settling: one endpoint's unfinalized word is plenty for
|
||||
// "we see it, hold on" and worthless for "paid". The probe is
|
||||
// skipped when the chain already settles on "latest" (dev, the
|
||||
// testnet suite): there is no gap between seen and paid to report.
|
||||
bool seenInFlight = false;
|
||||
for (const EurcChain& chain : chains_) {
|
||||
const std::optional<std::int64_t> required = RequiredUnits(chain, expectedMinor);
|
||||
if (!required) {
|
||||
|
|
@ -654,6 +661,14 @@ public:
|
|||
anyUnknown = true;
|
||||
break;
|
||||
case ChainVerdict::NotCovered:
|
||||
// Not settled at the settlement tag — but is it in flight?
|
||||
// One extra call on the first endpoint, only while the order
|
||||
// is live and only until something is spotted.
|
||||
if (!decisive && !seenInFlight && chain.blockTag != "latest") {
|
||||
const std::optional<std::int64_t> unfinalized =
|
||||
BalanceOf(chain, chain.rpcUrls.front(), address, "latest");
|
||||
if (unfinalized && *unfinalized >= *required) seenInFlight = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -686,7 +701,10 @@ public:
|
|||
"arrive there and needs settling by hand", address);
|
||||
return PaidStatus{ PayState::Dead, {} };
|
||||
}
|
||||
return PaidStatus{ PayState::Pending, {} };
|
||||
PaidStatus pending;
|
||||
pending.state = PayState::Pending;
|
||||
pending.seen = seenInFlight;
|
||||
return pending;
|
||||
}
|
||||
|
||||
// What the order page renders in place of a hosted-checkout button. Reads
|
||||
|
|
@ -823,18 +841,24 @@ private:
|
|||
return ChainVerdict::NotCovered;
|
||||
}
|
||||
|
||||
// tagOverride replaces the chain's settlement tag for this one call; the
|
||||
// in-flight probe uses it to peek at "latest". Empty means the settlement
|
||||
// tag, which every settling caller passes implicitly.
|
||||
std::optional<std::int64_t> BalanceOf(const EurcChain& chain,
|
||||
const std::string& url,
|
||||
const std::string& address) {
|
||||
const std::string& address,
|
||||
std::string_view tagOverride = {}) {
|
||||
// A node that is not serving this chain does not get to answer.
|
||||
if (!EndpointServesChain(chain, url)) return std::nullopt;
|
||||
// eth_call to the token contract; the calldata encoding lives in
|
||||
// BalanceOfCallData, where the self-test can pin it.
|
||||
const std::string data = BalanceOfCallData(address);
|
||||
const std::string_view tag =
|
||||
tagOverride.empty() ? std::string_view(chain.blockTag) : tagOverride;
|
||||
|
||||
const std::string body =
|
||||
std::string(R"({"jsonrpc":"2.0","id":1,"method":"eth_call","params":[{"to":")")
|
||||
+ chain.contract + R"(","data":")" + data + R"("},")" + chain.blockTag + R"("]})";
|
||||
+ chain.contract + R"(","data":")" + data + R"("},")" + std::string(tag) + R"("]})";
|
||||
|
||||
const std::optional<std::string> res = Call(chain, url, body);
|
||||
if (!res) return std::nullopt;
|
||||
|
|
|
|||
Loading…
Reference in a new issue