integraledger-terms 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- integraledger_terms/__init__.py +261 -0
- integraledger_terms/_agreement.py +306 -0
- integraledger_terms/_channels.py +409 -0
- integraledger_terms/_core.py +27 -0
- integraledger_terms/_gate.py +394 -0
- integraledger_terms/_keccak.py +61 -0
- integraledger_terms/_types.py +196 -0
- integraledger_terms/bindings/__init__.py +1 -0
- integraledger_terms/bindings/_algorand.py +406 -0
- integraledger_terms/bindings/_batch.py +59 -0
- integraledger_terms/bindings/_batch_evm.py +98 -0
- integraledger_terms/bindings/_bcs.py +317 -0
- integraledger_terms/bindings/_bolt11.py +208 -0
- integraledger_terms/bindings/_borsh_near.py +233 -0
- integraledger_terms/bindings/_cbor.py +173 -0
- integraledger_terms/bindings/_cbor_spans.py +133 -0
- integraledger_terms/bindings/_channel.py +49 -0
- integraledger_terms/bindings/_codec.py +248 -0
- integraledger_terms/bindings/_evm.py +455 -0
- integraledger_terms/bindings/_hedera_proto.py +338 -0
- integraledger_terms/bindings/_jose.py +494 -0
- integraledger_terms/bindings/_lcp.py +245 -0
- integraledger_terms/bindings/_mpp.py +545 -0
- integraledger_terms/bindings/_mpp_checks.py +751 -0
- integraledger_terms/bindings/_mpp_evm.py +199 -0
- integraledger_terms/bindings/_rail_bytes.py +53 -0
- integraledger_terms/bindings/_rlp.py +105 -0
- integraledger_terms/bindings/_scale.py +35 -0
- integraledger_terms/bindings/_session_within.py +107 -0
- integraledger_terms/bindings/_sfv.py +216 -0
- integraledger_terms/bindings/_ss58.py +21 -0
- integraledger_terms/bindings/_stacks.py +322 -0
- integraledger_terms/bindings/_stellar.py +354 -0
- integraledger_terms/bindings/_stellar_xdr.py +633 -0
- integraledger_terms/bindings/_sui_tx.py +443 -0
- integraledger_terms/bindings/_svm.py +750 -0
- integraledger_terms/bindings/_tempo.py +280 -0
- integraledger_terms/bindings/_ton_cell.py +378 -0
- integraledger_terms/bindings/_ton_tlb.py +158 -0
- integraledger_terms/bindings/_tron_proto.py +249 -0
- integraledger_terms/bindings/_url.py +126 -0
- integraledger_terms/bindings/_x402.py +145 -0
- integraledger_terms/bindings/_xrpl.py +115 -0
- integraledger_terms/bindings/_xrpl_codec.py +634 -0
- integraledger_terms/bindings/ack_payment_request.py +99 -0
- integraledger_terms/bindings/acp_checkout.py +213 -0
- integraledger_terms/bindings/ap2_checkout_mandate.py +204 -0
- integraledger_terms/bindings/card.py +465 -0
- integraledger_terms/bindings/lightning.py +400 -0
- integraledger_terms/bindings/mpp_card_stripe.py +51 -0
- integraledger_terms/bindings/mpp_charge_evm.py +308 -0
- integraledger_terms/bindings/mpp_charge_hedera.py +142 -0
- integraledger_terms/bindings/mpp_charge_nearintents.py +42 -0
- integraledger_terms/bindings/mpp_charge_solana.py +210 -0
- integraledger_terms/bindings/mpp_charge_stellar.py +103 -0
- integraledger_terms/bindings/mpp_charge_tempo.py +173 -0
- integraledger_terms/bindings/mpp_charge_usdc.py +348 -0
- integraledger_terms/bindings/mpp_charge_usdc_stacks.py +127 -0
- integraledger_terms/bindings/mpp_charge_xrpl.py +136 -0
- integraledger_terms/bindings/mpp_session.py +908 -0
- integraledger_terms/bindings/mpp_session_hedera.py +262 -0
- integraledger_terms/bindings/mpp_session_solana.py +280 -0
- integraledger_terms/bindings/mpp_session_xrpl.py +285 -0
- integraledger_terms/bindings/ucp.py +184 -0
- integraledger_terms/bindings/x402_batch_settlement_cloudflare.py +76 -0
- integraledger_terms/bindings/x402_batch_settlement_eip155.py +351 -0
- integraledger_terms/bindings/x402_batch_settlement_solana.py +447 -0
- integraledger_terms/bindings/x402_evm.py +733 -0
- integraledger_terms/bindings/x402_exact_algorand.py +223 -0
- integraledger_terms/bindings/x402_exact_aptos.py +254 -0
- integraledger_terms/bindings/x402_exact_cardano.py +249 -0
- integraledger_terms/bindings/x402_exact_casper.py +217 -0
- integraledger_terms/bindings/x402_exact_ccd.py +282 -0
- integraledger_terms/bindings/x402_exact_eip155_eip3009.py +265 -0
- integraledger_terms/bindings/x402_exact_hedera.py +315 -0
- integraledger_terms/bindings/x402_exact_near.py +204 -0
- integraledger_terms/bindings/x402_exact_polkadot_lcp_assets_remark.py +211 -0
- integraledger_terms/bindings/x402_exact_solana.py +151 -0
- integraledger_terms/bindings/x402_exact_starknet.py +276 -0
- integraledger_terms/bindings/x402_exact_stellar.py +120 -0
- integraledger_terms/bindings/x402_exact_sui.py +192 -0
- integraledger_terms/bindings/x402_exact_tron_lcp_trc20_memo.py +181 -0
- integraledger_terms/bindings/x402_exact_tvm.py +360 -0
- integraledger_terms/bindings/x402_exact_xrpl.py +166 -0
- integraledger_terms/bindings/x402_upto_solana.py +197 -0
- integraledger_terms/pieces/__init__.py +17 -0
- integraledger_terms/pieces/_base.py +21 -0
- integraledger_terms/pieces/_batch.py +96 -0
- integraledger_terms/pieces/_common.py +151 -0
- integraledger_terms/pieces/_family_evm.py +29 -0
- integraledger_terms/pieces/_family_hbar.py +22 -0
- integraledger_terms/pieces/_family_mpp.py +25 -0
- integraledger_terms/pieces/_family_proto.py +23 -0
- integraledger_terms/pieces/_family_rails.py +20 -0
- integraledger_terms/pieces/_family_sol.py +13 -0
- integraledger_terms/pieces/_family_xlm.py +14 -0
- integraledger_terms/pieces/_lnbtc_request.py +185 -0
- integraledger_terms/pieces/_mpp.py +269 -0
- integraledger_terms/pieces/_sol_rail.py +14 -0
- integraledger_terms/pieces/_x402_account_rails.py +81 -0
- integraledger_terms/pieces/_x402_rail.py +96 -0
- integraledger_terms/pieces/ack_payment_request.py +24 -0
- integraledger_terms/pieces/acp_checkout.py +68 -0
- integraledger_terms/pieces/ap2_checkout_mandate.py +38 -0
- integraledger_terms/pieces/card.py +104 -0
- integraledger_terms/pieces/evm_x402.py +54 -0
- integraledger_terms/pieces/lightning.py +138 -0
- integraledger_terms/pieces/mpp_card_stripe.py +10 -0
- integraledger_terms/pieces/mpp_charge_evm.py +11 -0
- integraledger_terms/pieces/mpp_charge_hedera.py +159 -0
- integraledger_terms/pieces/mpp_charge_nearintents.py +54 -0
- integraledger_terms/pieces/mpp_charge_solana.py +63 -0
- integraledger_terms/pieces/mpp_charge_stellar.py +32 -0
- integraledger_terms/pieces/mpp_charge_tempo.py +158 -0
- integraledger_terms/pieces/mpp_charge_usdc.py +56 -0
- integraledger_terms/pieces/mpp_charge_usdc_stacks.py +29 -0
- integraledger_terms/pieces/mpp_charge_xrpl.py +38 -0
- integraledger_terms/pieces/mpp_session.py +77 -0
- integraledger_terms/pieces/mpp_session_hedera.py +63 -0
- integraledger_terms/pieces/mpp_session_solana.py +79 -0
- integraledger_terms/pieces/mpp_session_xrpl.py +60 -0
- integraledger_terms/pieces/protocol_groups.py +49 -0
- integraledger_terms/pieces/ucp.py +51 -0
- integraledger_terms/pieces/x402_batch_settlement_cloudflare.py +42 -0
- integraledger_terms/pieces/x402_batch_settlement_eip155.py +54 -0
- integraledger_terms/pieces/x402_batch_settlement_solana.py +81 -0
- integraledger_terms/pieces/x402_exact_algorand.py +53 -0
- integraledger_terms/pieces/x402_exact_aptos.py +11 -0
- integraledger_terms/pieces/x402_exact_cardano.py +13 -0
- integraledger_terms/pieces/x402_exact_casper.py +39 -0
- integraledger_terms/pieces/x402_exact_ccd.py +36 -0
- integraledger_terms/pieces/x402_exact_eip155_eip3009.py +62 -0
- integraledger_terms/pieces/x402_exact_hedera.py +62 -0
- integraledger_terms/pieces/x402_exact_hedera_transfer_executor.py +39 -0
- integraledger_terms/pieces/x402_exact_near.py +51 -0
- integraledger_terms/pieces/x402_exact_polkadot_lcp_assets_remark.py +37 -0
- integraledger_terms/pieces/x402_exact_solana.py +38 -0
- integraledger_terms/pieces/x402_exact_starknet.py +38 -0
- integraledger_terms/pieces/x402_exact_stellar.py +31 -0
- integraledger_terms/pieces/x402_exact_sui.py +11 -0
- integraledger_terms/pieces/x402_exact_tron_lcp_trc20_memo.py +65 -0
- integraledger_terms/pieces/x402_exact_tvm.py +58 -0
- integraledger_terms/pieces/x402_exact_xrpl.py +43 -0
- integraledger_terms/pieces/x402_upto_solana.py +52 -0
- integraledger_terms/py.typed +0 -0
- integraledger_terms-0.1.0.dist-info/METADATA +583 -0
- integraledger_terms-0.1.0.dist-info/RECORD +149 -0
- integraledger_terms-0.1.0.dist-info/WHEEL +4 -0
- integraledger_terms-0.1.0.dist-info/licenses/LICENSE +202 -0
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
"""The Python buyer gate: before a buyer signs, confirm that the advertised ATR hash is the SHA-256 of the bytes the
|
|
2
|
+
seller's link serves, build the payment with that hash, and confirm the hash inside what was signed."""
|
|
3
|
+
|
|
4
|
+
from ._agreement import agree
|
|
5
|
+
from ._channels import ChannelHold, Within, open_channel, record_charge, within
|
|
6
|
+
from ._core import MAX_ATR_BYTES, AtrHash, atr_hash, hash_equals
|
|
7
|
+
from ._gate import check, confirm, finish, transact
|
|
8
|
+
from ._types import (
|
|
9
|
+
Advertised,
|
|
10
|
+
Agreed,
|
|
11
|
+
AgreementReceipt,
|
|
12
|
+
Binding,
|
|
13
|
+
Checked,
|
|
14
|
+
Chosen,
|
|
15
|
+
Confirmed,
|
|
16
|
+
DeclineCode,
|
|
17
|
+
Declined,
|
|
18
|
+
Finished,
|
|
19
|
+
Inputs,
|
|
20
|
+
Json,
|
|
21
|
+
Next,
|
|
22
|
+
Refusal,
|
|
23
|
+
Signature,
|
|
24
|
+
Signer,
|
|
25
|
+
Step,
|
|
26
|
+
Transacted,
|
|
27
|
+
Unsigned,
|
|
28
|
+
)
|
|
29
|
+
from .bindings.mpp_card_stripe import charge_card, charge_stripe, subscription_stripe
|
|
30
|
+
from .bindings.mpp_charge_evm import (
|
|
31
|
+
MppChargeEvmAuthorization,
|
|
32
|
+
MppChargeEvmHash,
|
|
33
|
+
MppChargeEvmPermit2,
|
|
34
|
+
MppChargeEvmTransaction,
|
|
35
|
+
)
|
|
36
|
+
from .bindings.mpp_charge_nearintents import MppChargeNearIntents
|
|
37
|
+
from .bindings.mpp_charge_tempo import MppChargeTempoMemo, MppChargeTempoPush
|
|
38
|
+
from .bindings.mpp_charge_usdc import MppChargeUsdcEvm, MppChargeUsdcGateway
|
|
39
|
+
from .bindings.mpp_session import MppSessionEvm, MppSessionTempo, MppSubscriptionTempo
|
|
40
|
+
from .bindings._channel import BatchUnsigned, ChannelRef
|
|
41
|
+
from .bindings.ack_payment_request import AckPaymentRequest
|
|
42
|
+
from .bindings.acp_checkout import AcpCheckoutDelegated, AcpCheckoutUndelegated
|
|
43
|
+
from .bindings.ap2_checkout_mandate import Ap2CheckoutMandate
|
|
44
|
+
from .bindings.card import CardMastercardViAutonomous, CardMastercardViImmediate, CardSellerReference, CardVisaTap
|
|
45
|
+
from .bindings.lightning import (
|
|
46
|
+
MPP_CHARGE,
|
|
47
|
+
MppLightning,
|
|
48
|
+
MppLightningSession,
|
|
49
|
+
X402ExactLnbtc,
|
|
50
|
+
X402ExactLnbtcInvoiceNamed,
|
|
51
|
+
)
|
|
52
|
+
from .bindings.ucp import (
|
|
53
|
+
BOOKING_AP2_MANDATE,
|
|
54
|
+
BOOKING_UNSIGNED,
|
|
55
|
+
CHECKOUT_AP2_MANDATE,
|
|
56
|
+
CHECKOUT_UNSIGNED,
|
|
57
|
+
UcpAp2Mandate,
|
|
58
|
+
UcpUnsignedPairing,
|
|
59
|
+
)
|
|
60
|
+
from .bindings.x402_batch_settlement_cloudflare import X402BatchSettlementCloudflare
|
|
61
|
+
from .bindings.x402_batch_settlement_eip155 import X402BatchSettlementEip155
|
|
62
|
+
from .bindings.x402_evm import (
|
|
63
|
+
X402_AUTH_CAPTURE_EIP155_EIP3009,
|
|
64
|
+
X402_AUTH_CAPTURE_EIP155_PERMIT2,
|
|
65
|
+
X402_EXACT_EIP155_ERC7710,
|
|
66
|
+
X402_EXACT_EIP155_ERC7710_SALT,
|
|
67
|
+
X402_EXACT_EIP155_PERMIT2,
|
|
68
|
+
X402_UPTO_EIP155_PERMIT2,
|
|
69
|
+
)
|
|
70
|
+
from .bindings.x402_exact_eip155_eip3009 import X402ExactEip155Eip3009
|
|
71
|
+
from .bindings.mpp_charge_solana import MPP_CHARGE_SOLANA, MPP_CHARGE_USDC_SOLANA
|
|
72
|
+
from .bindings.mpp_session_solana import MPP_SESSION_SOLANA
|
|
73
|
+
from .bindings.x402_batch_settlement_solana import X402BatchSettlementSolana
|
|
74
|
+
from .bindings.x402_exact_solana import X402ExactSolana
|
|
75
|
+
from .bindings.x402_upto_solana import X402UptoSolana
|
|
76
|
+
from .bindings.mpp_charge_hedera import MppChargeHedera
|
|
77
|
+
from .bindings.mpp_session_hedera import MppSessionHedera
|
|
78
|
+
from .bindings.x402_exact_hedera import X402ExactHedera, X402ExactHederaExecutor
|
|
79
|
+
from .bindings.x402_exact_near import X402ExactNear
|
|
80
|
+
from .bindings.x402_exact_tron_lcp_trc20_memo import X402ExactTronLcpTrc20Memo
|
|
81
|
+
from .bindings.x402_exact_tvm import X402ExactTvm
|
|
82
|
+
from .bindings.x402_exact_starknet import X402ExactStarknet
|
|
83
|
+
from .bindings.x402_exact_casper import X402ExactCasper
|
|
84
|
+
from .bindings.x402_exact_aptos import X402ExactAptos
|
|
85
|
+
from .bindings.x402_exact_polkadot_lcp_assets_remark import X402ExactPolkadotLcpAssetsRemark
|
|
86
|
+
from .bindings.x402_exact_ccd import X402ExactCcd
|
|
87
|
+
from .bindings.x402_exact_cardano import X402ExactCardano
|
|
88
|
+
from .bindings.x402_exact_sui import X402ExactSui
|
|
89
|
+
from .bindings.mpp_charge_stellar import MppChargeStellar
|
|
90
|
+
from .bindings.mpp_charge_usdc_stacks import MppChargeUsdcStacks
|
|
91
|
+
from .bindings.mpp_charge_xrpl import MppChargeXrpl
|
|
92
|
+
from .bindings.mpp_session_xrpl import MppSessionXrpl
|
|
93
|
+
from .bindings.x402_exact_algorand import X402ExactAlgorand
|
|
94
|
+
from .bindings.x402_exact_stellar import X402ExactStellar
|
|
95
|
+
from .bindings.x402_exact_xrpl import X402ExactXrpl
|
|
96
|
+
|
|
97
|
+
X402_EXACT_EIP155_EIP3009: Binding = X402ExactEip155Eip3009()
|
|
98
|
+
X402_EXACT_HEDERA: Binding = X402ExactHedera()
|
|
99
|
+
MPP_CHARGE_HEDERA: Binding = MppChargeHedera()
|
|
100
|
+
MPP_SESSION_HEDERA: Binding = MppSessionHedera()
|
|
101
|
+
X402_EXACT_HEDERA_TRANSFER_EXECUTOR: Binding = X402ExactHederaExecutor()
|
|
102
|
+
X402_EXACT_NEAR: Binding = X402ExactNear()
|
|
103
|
+
X402_EXACT_TRON_LCP_TRC20_MEMO: Binding = X402ExactTronLcpTrc20Memo()
|
|
104
|
+
X402_EXACT_TVM: Binding = X402ExactTvm()
|
|
105
|
+
ACK_PAYMENT_REQUEST: Binding = AckPaymentRequest()
|
|
106
|
+
ACP_CHECKOUT_DELEGATED: Binding = AcpCheckoutDelegated()
|
|
107
|
+
ACP_CHECKOUT_UNDELEGATED: Binding = AcpCheckoutUndelegated()
|
|
108
|
+
CARD_VISA_TAP: Binding = CardVisaTap()
|
|
109
|
+
AP2_CHECKOUT_MANDATE: Binding = Ap2CheckoutMandate()
|
|
110
|
+
UCP_CHECKOUT_AP2_MANDATE: Binding = UcpAp2Mandate(CHECKOUT_AP2_MANDATE)
|
|
111
|
+
UCP_CHECKOUT_UNSIGNED: Binding = UcpUnsignedPairing(CHECKOUT_UNSIGNED)
|
|
112
|
+
UCP_BOOKING_AP2_MANDATE: Binding = UcpAp2Mandate(BOOKING_AP2_MANDATE)
|
|
113
|
+
UCP_BOOKING_UNSIGNED: Binding = UcpUnsignedPairing(BOOKING_UNSIGNED)
|
|
114
|
+
X402_EXACT_LNBTC: Binding = X402ExactLnbtc()
|
|
115
|
+
X402_EXACT_LNBTC_INVOICE_NAMED: Binding = X402ExactLnbtcInvoiceNamed()
|
|
116
|
+
MPP_CHARGE_LIGHTNING: Binding = MppLightning(MPP_CHARGE)
|
|
117
|
+
MPP_SESSION_LIGHTNING: Binding = MppLightningSession()
|
|
118
|
+
CARD_MASTERCARD_VI_IMMEDIATE: Binding = CardMastercardViImmediate()
|
|
119
|
+
CARD_MASTERCARD_VI_AUTONOMOUS: Binding = CardMastercardViAutonomous()
|
|
120
|
+
CARD_SELLER_REFERENCE: Binding = CardSellerReference()
|
|
121
|
+
X402_BATCH_SETTLEMENT_EIP155 = X402BatchSettlementEip155()
|
|
122
|
+
X402_BATCH_SETTLEMENT_CLOUDFLARE = X402BatchSettlementCloudflare()
|
|
123
|
+
X402_EXACT_SOLANA: Binding = X402ExactSolana()
|
|
124
|
+
X402_BATCH_SETTLEMENT_SOLANA: Binding = X402BatchSettlementSolana()
|
|
125
|
+
X402_UPTO_SOLANA: Binding = X402UptoSolana()
|
|
126
|
+
|
|
127
|
+
MPP_CHARGE_EVM_AUTHORIZATION: Binding = MppChargeEvmAuthorization()
|
|
128
|
+
MPP_CHARGE_EVM_PERMIT2: Binding = MppChargeEvmPermit2()
|
|
129
|
+
MPP_CHARGE_EVM_TRANSACTION: Binding = MppChargeEvmTransaction()
|
|
130
|
+
MPP_CHARGE_EVM_HASH: Binding = MppChargeEvmHash()
|
|
131
|
+
MPP_CHARGE_CARD: Binding = charge_card()
|
|
132
|
+
MPP_CHARGE_STRIPE: Binding = charge_stripe()
|
|
133
|
+
MPP_SUBSCRIPTION_STRIPE: Binding = subscription_stripe()
|
|
134
|
+
MPP_CHARGE_NEARINTENTS: Binding = MppChargeNearIntents()
|
|
135
|
+
MPP_CHARGE_TEMPO_MEMO: Binding = MppChargeTempoMemo()
|
|
136
|
+
MPP_CHARGE_TEMPO_PUSH: Binding = MppChargeTempoPush()
|
|
137
|
+
MPP_CHARGE_USDC_EVM: Binding = MppChargeUsdcEvm()
|
|
138
|
+
MPP_CHARGE_USDC_GATEWAY: Binding = MppChargeUsdcGateway()
|
|
139
|
+
MPP_SESSION_EVM: Binding = MppSessionEvm()
|
|
140
|
+
MPP_SESSION_TEMPO: Binding = MppSessionTempo()
|
|
141
|
+
MPP_SUBSCRIPTION_TEMPO: Binding = MppSubscriptionTempo()
|
|
142
|
+
X402_EXACT_STARKNET: Binding = X402ExactStarknet()
|
|
143
|
+
X402_EXACT_CASPER: Binding = X402ExactCasper()
|
|
144
|
+
X402_EXACT_APTOS: Binding = X402ExactAptos()
|
|
145
|
+
X402_EXACT_POLKADOT_LCP_ASSETS_REMARK: Binding = X402ExactPolkadotLcpAssetsRemark()
|
|
146
|
+
X402_EXACT_CCD: Binding = X402ExactCcd()
|
|
147
|
+
X402_EXACT_CARDANO: Binding = X402ExactCardano()
|
|
148
|
+
X402_EXACT_SUI: Binding = X402ExactSui()
|
|
149
|
+
|
|
150
|
+
X402_EXACT_XRPL: Binding = X402ExactXrpl()
|
|
151
|
+
X402_EXACT_ALGORAND: Binding = X402ExactAlgorand()
|
|
152
|
+
X402_EXACT_STELLAR: Binding = X402ExactStellar()
|
|
153
|
+
MPP_CHARGE_XRPL: Binding = MppChargeXrpl()
|
|
154
|
+
MPP_CHARGE_STELLAR: Binding = MppChargeStellar()
|
|
155
|
+
MPP_CHARGE_USDC_STACKS: Binding = MppChargeUsdcStacks()
|
|
156
|
+
MPP_SESSION_XRPL: Binding = MppSessionXrpl()
|
|
157
|
+
|
|
158
|
+
__all__ = [
|
|
159
|
+
"ACK_PAYMENT_REQUEST",
|
|
160
|
+
"ACP_CHECKOUT_DELEGATED",
|
|
161
|
+
"ACP_CHECKOUT_UNDELEGATED",
|
|
162
|
+
"AP2_CHECKOUT_MANDATE",
|
|
163
|
+
"CARD_MASTERCARD_VI_AUTONOMOUS",
|
|
164
|
+
"CARD_MASTERCARD_VI_IMMEDIATE",
|
|
165
|
+
"CARD_SELLER_REFERENCE",
|
|
166
|
+
"CARD_VISA_TAP",
|
|
167
|
+
"MAX_ATR_BYTES",
|
|
168
|
+
"MPP_CHARGE_CARD",
|
|
169
|
+
"MPP_CHARGE_EVM_AUTHORIZATION",
|
|
170
|
+
"MPP_CHARGE_EVM_HASH",
|
|
171
|
+
"MPP_CHARGE_EVM_PERMIT2",
|
|
172
|
+
"MPP_CHARGE_EVM_TRANSACTION",
|
|
173
|
+
"MPP_CHARGE_HEDERA",
|
|
174
|
+
"MPP_CHARGE_LIGHTNING",
|
|
175
|
+
"MPP_CHARGE_NEARINTENTS",
|
|
176
|
+
"MPP_CHARGE_SOLANA",
|
|
177
|
+
"MPP_CHARGE_STRIPE",
|
|
178
|
+
"MPP_CHARGE_TEMPO_MEMO",
|
|
179
|
+
"MPP_CHARGE_TEMPO_PUSH",
|
|
180
|
+
"MPP_CHARGE_USDC_EVM",
|
|
181
|
+
"MPP_CHARGE_USDC_GATEWAY",
|
|
182
|
+
"MPP_CHARGE_USDC_SOLANA",
|
|
183
|
+
"MPP_SESSION_EVM",
|
|
184
|
+
"MPP_SESSION_HEDERA",
|
|
185
|
+
"MPP_SESSION_LIGHTNING",
|
|
186
|
+
"MPP_SESSION_SOLANA",
|
|
187
|
+
"MPP_SESSION_TEMPO",
|
|
188
|
+
"MPP_SUBSCRIPTION_STRIPE",
|
|
189
|
+
"MPP_SUBSCRIPTION_TEMPO",
|
|
190
|
+
"UCP_BOOKING_AP2_MANDATE",
|
|
191
|
+
"UCP_BOOKING_UNSIGNED",
|
|
192
|
+
"UCP_CHECKOUT_AP2_MANDATE",
|
|
193
|
+
"UCP_CHECKOUT_UNSIGNED",
|
|
194
|
+
"X402_AUTH_CAPTURE_EIP155_EIP3009",
|
|
195
|
+
"X402_AUTH_CAPTURE_EIP155_PERMIT2",
|
|
196
|
+
"X402_BATCH_SETTLEMENT_CLOUDFLARE",
|
|
197
|
+
"X402_BATCH_SETTLEMENT_EIP155",
|
|
198
|
+
"X402_BATCH_SETTLEMENT_SOLANA",
|
|
199
|
+
"X402_EXACT_APTOS",
|
|
200
|
+
"X402_EXACT_CARDANO",
|
|
201
|
+
"X402_EXACT_CASPER",
|
|
202
|
+
"X402_EXACT_CCD",
|
|
203
|
+
"X402_EXACT_EIP155_EIP3009",
|
|
204
|
+
"X402_EXACT_EIP155_ERC7710",
|
|
205
|
+
"X402_EXACT_EIP155_ERC7710_SALT",
|
|
206
|
+
"X402_EXACT_EIP155_PERMIT2",
|
|
207
|
+
"X402_EXACT_HEDERA",
|
|
208
|
+
"X402_EXACT_HEDERA_TRANSFER_EXECUTOR",
|
|
209
|
+
"X402_EXACT_LNBTC",
|
|
210
|
+
"X402_EXACT_LNBTC_INVOICE_NAMED",
|
|
211
|
+
"X402_EXACT_NEAR",
|
|
212
|
+
"X402_EXACT_POLKADOT_LCP_ASSETS_REMARK",
|
|
213
|
+
"X402_EXACT_SOLANA",
|
|
214
|
+
"X402_EXACT_STARKNET",
|
|
215
|
+
"X402_EXACT_SUI",
|
|
216
|
+
"X402_EXACT_TRON_LCP_TRC20_MEMO",
|
|
217
|
+
"X402_EXACT_TVM",
|
|
218
|
+
"X402_UPTO_EIP155_PERMIT2",
|
|
219
|
+
"X402_UPTO_SOLANA",
|
|
220
|
+
"X402_EXACT_XRPL",
|
|
221
|
+
"X402_EXACT_ALGORAND",
|
|
222
|
+
"X402_EXACT_STELLAR",
|
|
223
|
+
"MPP_CHARGE_XRPL",
|
|
224
|
+
"MPP_CHARGE_STELLAR",
|
|
225
|
+
"MPP_CHARGE_USDC_STACKS",
|
|
226
|
+
"MPP_SESSION_XRPL",
|
|
227
|
+
"Advertised",
|
|
228
|
+
"Agreed",
|
|
229
|
+
"AgreementReceipt",
|
|
230
|
+
"AtrHash",
|
|
231
|
+
"BatchUnsigned",
|
|
232
|
+
"Binding",
|
|
233
|
+
"ChannelHold",
|
|
234
|
+
"ChannelRef",
|
|
235
|
+
"Checked",
|
|
236
|
+
"Chosen",
|
|
237
|
+
"Confirmed",
|
|
238
|
+
"DeclineCode",
|
|
239
|
+
"Declined",
|
|
240
|
+
"Finished",
|
|
241
|
+
"Inputs",
|
|
242
|
+
"Json",
|
|
243
|
+
"Next",
|
|
244
|
+
"Refusal",
|
|
245
|
+
"Signature",
|
|
246
|
+
"Signer",
|
|
247
|
+
"Step",
|
|
248
|
+
"Transacted",
|
|
249
|
+
"Unsigned",
|
|
250
|
+
"Within",
|
|
251
|
+
"agree",
|
|
252
|
+
"atr_hash",
|
|
253
|
+
"check",
|
|
254
|
+
"confirm",
|
|
255
|
+
"finish",
|
|
256
|
+
"hash_equals",
|
|
257
|
+
"open_channel",
|
|
258
|
+
"record_charge",
|
|
259
|
+
"transact",
|
|
260
|
+
"within",
|
|
261
|
+
]
|
|
@@ -0,0 +1,306 @@
|
|
|
1
|
+
"""The agreement payment: ask the agreement URL for its challenge, pay it through the buyer piece of the pairing that
|
|
2
|
+
placed it, a pairing whose payment is itself a public proof of the ATR hash, and return the resource's receipt once the
|
|
3
|
+
payment is recorded. Nothing is signed when the challenge advertises another hash, and nothing is sent unless what was
|
|
4
|
+
signed carries the hash. Once sent, the same signed payment is sent again after each 202, 5xx or timeout, each paid
|
|
5
|
+
request bounded by min(maxTimeoutSeconds, 120) + 60 + 10 seconds and the whole exchange by the agreement option's
|
|
6
|
+
maxTimeoutSeconds + 180 seconds; no second agreement payment is signed, and every decline after it was sent carries it
|
|
7
|
+
as moved."""
|
|
8
|
+
|
|
9
|
+
import asyncio
|
|
10
|
+
import base64
|
|
11
|
+
import binascii
|
|
12
|
+
import json
|
|
13
|
+
import re
|
|
14
|
+
import time
|
|
15
|
+
from collections.abc import Mapping, Sequence
|
|
16
|
+
from dataclasses import dataclass, replace
|
|
17
|
+
from typing import Any
|
|
18
|
+
|
|
19
|
+
import httpx
|
|
20
|
+
|
|
21
|
+
from . import _gate
|
|
22
|
+
from ._core import AtrHash, hash_equals, is_hash
|
|
23
|
+
from .bindings._jose import UNPARSED, parse_json
|
|
24
|
+
from .bindings._lcp import is_https_link, is_other_scheme_link
|
|
25
|
+
from ._types import Advertised, AgreementReceipt, Agreed, Binding, Declined, Inputs, Moved, Refusal, Signer
|
|
26
|
+
|
|
27
|
+
UNPAID_DEADLINE_S = 10.0
|
|
28
|
+
EXCHANGE_CAP_S = 120
|
|
29
|
+
SETTLE_S = 60
|
|
30
|
+
VERIFY_S = 10
|
|
31
|
+
WINDOW_EXTRA_S = 180
|
|
32
|
+
MAX_ANSWER_BYTES = 65_536
|
|
33
|
+
RETRY_DEFAULT_S = 2
|
|
34
|
+
RETRY_MIN_S = 1
|
|
35
|
+
|
|
36
|
+
_DECIMAL = re.compile(r"[0-9]{1,9}")
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def _clock() -> float:
|
|
40
|
+
return time.monotonic()
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
async def _sleep(seconds: float) -> None:
|
|
44
|
+
await asyncio.sleep(seconds)
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
@dataclass(frozen=True, slots=True)
|
|
48
|
+
class _Answer:
|
|
49
|
+
status: int
|
|
50
|
+
payment_required: str | None
|
|
51
|
+
retry_after: str | None
|
|
52
|
+
body: bytes | None
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
@dataclass(frozen=True, slots=True)
|
|
56
|
+
class _Unanswered:
|
|
57
|
+
"""A request that reached no answer: its deadline passed, or the URL could not be reached."""
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def _failed(detail: str, moved: Moved | None = None) -> Declined:
|
|
61
|
+
return Declined("agreement-failed", detail, moved)
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def _server_error(status: int) -> bool:
|
|
65
|
+
"""A 5xx answer to the paid request, which is read as a timeout: the same payment is sent again."""
|
|
66
|
+
return 500 <= status <= 599
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def _to_base64(value: object) -> str:
|
|
70
|
+
"""Standard base64 of the UTF-8 bytes of the compact JSON of value."""
|
|
71
|
+
text = json.dumps(value, separators=(",", ":"), ensure_ascii=False)
|
|
72
|
+
return base64.b64encode(text.encode("utf-8")).decode("ascii")
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def _from_base64_json(header: str) -> object | None:
|
|
76
|
+
"""The JSON value a base64 header carries, or None when it is not base64 of UTF-8 JSON."""
|
|
77
|
+
if len(header) > MAX_ANSWER_BYTES:
|
|
78
|
+
return None
|
|
79
|
+
try:
|
|
80
|
+
loaded: object = parse_json(base64.b64decode(header, validate=True).decode("utf-8"))
|
|
81
|
+
except (binascii.Error, UnicodeDecodeError, ValueError):
|
|
82
|
+
return None
|
|
83
|
+
return None if loaded is UNPARSED else loaded
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def _retry_seconds(header: str | None) -> int:
|
|
87
|
+
"""retry-after in whole seconds, at least 1; 2 when absent or not a number of seconds."""
|
|
88
|
+
value = header.strip() if header is not None else None
|
|
89
|
+
if value is None or _DECIMAL.fullmatch(value) is None:
|
|
90
|
+
return RETRY_DEFAULT_S
|
|
91
|
+
return max(RETRY_MIN_S, int(value))
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
async def _get(
|
|
95
|
+
fetch: httpx.AsyncClient, url: str, signature: str | None, seconds: float
|
|
96
|
+
) -> _Answer | _Unanswered | Declined:
|
|
97
|
+
"""One GET of the agreement URL, with no redirect and a deadline of seconds over headers and body. A 200 body is
|
|
98
|
+
read up to 64 KiB; any other body is left unread."""
|
|
99
|
+
headers = None if signature is None else {"PAYMENT-SIGNATURE": signature}
|
|
100
|
+
too_large = _failed("The agreement receipt is larger than 64 KiB.")
|
|
101
|
+
try:
|
|
102
|
+
async with asyncio.timeout(seconds):
|
|
103
|
+
async with fetch.stream("GET", url, headers=headers, follow_redirects=False) as response:
|
|
104
|
+
answer = _Answer(
|
|
105
|
+
status=response.status_code,
|
|
106
|
+
payment_required=response.headers.get("payment-required"),
|
|
107
|
+
retry_after=response.headers.get("retry-after"),
|
|
108
|
+
body=None,
|
|
109
|
+
)
|
|
110
|
+
if response.status_code != 200:
|
|
111
|
+
return answer
|
|
112
|
+
declared = response.headers.get("content-length")
|
|
113
|
+
if declared is not None and declared.strip().isdigit() and int(declared) > MAX_ANSWER_BYTES:
|
|
114
|
+
return too_large
|
|
115
|
+
body = bytearray()
|
|
116
|
+
async for chunk in response.aiter_bytes():
|
|
117
|
+
body += chunk
|
|
118
|
+
if len(body) > MAX_ANSWER_BYTES:
|
|
119
|
+
return too_large
|
|
120
|
+
return replace(answer, body=bytes(body))
|
|
121
|
+
except Exception:
|
|
122
|
+
return _Unanswered()
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
def _receipt(body: bytes | None, h: AtrHash) -> Agreed | Declined:
|
|
126
|
+
"""The receipt a 200 carries, when it is the agreement receipt for h."""
|
|
127
|
+
try:
|
|
128
|
+
parsed: object = parse_json((body or b"").decode("utf-8"))
|
|
129
|
+
except (UnicodeDecodeError, ValueError):
|
|
130
|
+
return _failed("The agreement URL answered 200 without a JSON receipt.")
|
|
131
|
+
if parsed is UNPARSED or not isinstance(parsed, Mapping):
|
|
132
|
+
return _failed("The agreement URL answered 200 without a JSON receipt.")
|
|
133
|
+
atr_hash = parsed.get("atrHash")
|
|
134
|
+
if not isinstance(atr_hash, str) or not is_hash(atr_hash) or not hash_equals(atr_hash, h):
|
|
135
|
+
return _failed("The agreement receipt names another ATR hash.")
|
|
136
|
+
network = parsed.get("network")
|
|
137
|
+
transaction = parsed.get("transaction")
|
|
138
|
+
if parsed.get("agreed") is not True or not isinstance(network, str) or not isinstance(transaction, str):
|
|
139
|
+
return _failed("The agreement receipt is not a recorded agreement.")
|
|
140
|
+
return Agreed(AgreementReceipt(atr_hash=atr_hash, agreed=True, network=network, transaction=transaction))
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
def _x402_bindings() -> tuple[Binding, ...]:
|
|
144
|
+
"""The x402 pairings the gate serves, in the protocol package's order."""
|
|
145
|
+
from . import (
|
|
146
|
+
X402_AUTH_CAPTURE_EIP155_EIP3009,
|
|
147
|
+
X402_AUTH_CAPTURE_EIP155_PERMIT2,
|
|
148
|
+
X402_BATCH_SETTLEMENT_CLOUDFLARE,
|
|
149
|
+
X402_BATCH_SETTLEMENT_EIP155,
|
|
150
|
+
X402_BATCH_SETTLEMENT_SOLANA,
|
|
151
|
+
X402_EXACT_ALGORAND,
|
|
152
|
+
X402_EXACT_APTOS,
|
|
153
|
+
X402_EXACT_CARDANO,
|
|
154
|
+
X402_EXACT_CASPER,
|
|
155
|
+
X402_EXACT_CCD,
|
|
156
|
+
X402_EXACT_EIP155_EIP3009,
|
|
157
|
+
X402_EXACT_EIP155_ERC7710,
|
|
158
|
+
X402_EXACT_EIP155_ERC7710_SALT,
|
|
159
|
+
X402_EXACT_EIP155_PERMIT2,
|
|
160
|
+
X402_EXACT_HEDERA,
|
|
161
|
+
X402_EXACT_HEDERA_TRANSFER_EXECUTOR,
|
|
162
|
+
X402_EXACT_LNBTC,
|
|
163
|
+
X402_EXACT_LNBTC_INVOICE_NAMED,
|
|
164
|
+
X402_EXACT_NEAR,
|
|
165
|
+
X402_EXACT_POLKADOT_LCP_ASSETS_REMARK,
|
|
166
|
+
X402_EXACT_SOLANA,
|
|
167
|
+
X402_EXACT_STARKNET,
|
|
168
|
+
X402_EXACT_STELLAR,
|
|
169
|
+
X402_EXACT_SUI,
|
|
170
|
+
X402_EXACT_TRON_LCP_TRC20_MEMO,
|
|
171
|
+
X402_EXACT_TVM,
|
|
172
|
+
X402_EXACT_XRPL,
|
|
173
|
+
X402_UPTO_EIP155_PERMIT2,
|
|
174
|
+
X402_UPTO_SOLANA,
|
|
175
|
+
)
|
|
176
|
+
|
|
177
|
+
return (
|
|
178
|
+
X402_EXACT_EIP155_EIP3009,
|
|
179
|
+
X402_AUTH_CAPTURE_EIP155_EIP3009,
|
|
180
|
+
X402_AUTH_CAPTURE_EIP155_PERMIT2,
|
|
181
|
+
X402_BATCH_SETTLEMENT_CLOUDFLARE,
|
|
182
|
+
X402_BATCH_SETTLEMENT_EIP155,
|
|
183
|
+
X402_BATCH_SETTLEMENT_SOLANA,
|
|
184
|
+
X402_EXACT_ALGORAND,
|
|
185
|
+
X402_EXACT_APTOS,
|
|
186
|
+
X402_EXACT_CARDANO,
|
|
187
|
+
X402_EXACT_CASPER,
|
|
188
|
+
X402_EXACT_CCD,
|
|
189
|
+
X402_EXACT_EIP155_ERC7710,
|
|
190
|
+
X402_EXACT_EIP155_ERC7710_SALT,
|
|
191
|
+
X402_EXACT_EIP155_PERMIT2,
|
|
192
|
+
X402_EXACT_HEDERA,
|
|
193
|
+
X402_EXACT_HEDERA_TRANSFER_EXECUTOR,
|
|
194
|
+
X402_EXACT_LNBTC,
|
|
195
|
+
X402_EXACT_LNBTC_INVOICE_NAMED,
|
|
196
|
+
X402_EXACT_NEAR,
|
|
197
|
+
X402_EXACT_POLKADOT_LCP_ASSETS_REMARK,
|
|
198
|
+
X402_EXACT_SOLANA,
|
|
199
|
+
X402_EXACT_STARKNET,
|
|
200
|
+
X402_EXACT_STELLAR,
|
|
201
|
+
X402_EXACT_SUI,
|
|
202
|
+
X402_EXACT_TRON_LCP_TRC20_MEMO,
|
|
203
|
+
X402_EXACT_TVM,
|
|
204
|
+
X402_EXACT_XRPL,
|
|
205
|
+
X402_UPTO_EIP155_PERMIT2,
|
|
206
|
+
X402_UPTO_SOLANA,
|
|
207
|
+
)
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
def _agreement_pairing(required: Mapping[str, Any]) -> tuple[Binding, Advertised, Mapping[str, Any]] | Declined:
|
|
211
|
+
"""The pairing that placed the agreement option, when its payment is itself a public proof, with its read and the
|
|
212
|
+
option."""
|
|
213
|
+
accepts = required.get("accepts")
|
|
214
|
+
if not isinstance(accepts, Sequence) or isinstance(accepts, str) or not accepts or not isinstance(accepts[0], Mapping):
|
|
215
|
+
return Declined("offer-unreadable", "x402/no-payable-option")
|
|
216
|
+
for binding in _x402_bindings():
|
|
217
|
+
try:
|
|
218
|
+
read = binding.read(required)
|
|
219
|
+
except Exception:
|
|
220
|
+
continue
|
|
221
|
+
if isinstance(read, Advertised):
|
|
222
|
+
if getattr(binding, "public_proof", False) is not True:
|
|
223
|
+
return Declined("pairing-not-supported", f"The agreement pairing {binding.id} is not itself a public proof.")
|
|
224
|
+
return binding, read, accepts[0]
|
|
225
|
+
return Declined("pairing-not-supported", "The agreement option names no pairing the gate serves.")
|
|
226
|
+
|
|
227
|
+
|
|
228
|
+
def _bounds(option: Mapping[str, Any]) -> tuple[int, int] | None:
|
|
229
|
+
"""The paid request's deadline and the whole exchange's, in seconds, from the option's maxTimeoutSeconds."""
|
|
230
|
+
t = option.get("maxTimeoutSeconds")
|
|
231
|
+
if isinstance(t, bool) or not isinstance(t, int) or t <= 0 or t > 2**53 - 1:
|
|
232
|
+
return None
|
|
233
|
+
return min(t, EXCHANGE_CAP_S) + SETTLE_S + VERIFY_S, t + WINDOW_EXTRA_S
|
|
234
|
+
|
|
235
|
+
|
|
236
|
+
async def agree(
|
|
237
|
+
h: AtrHash,
|
|
238
|
+
url: str,
|
|
239
|
+
signer: Signer,
|
|
240
|
+
fetch: httpx.AsyncClient,
|
|
241
|
+
*,
|
|
242
|
+
atr_bytes: bytes,
|
|
243
|
+
inputs: Inputs | None = None,
|
|
244
|
+
ns: str | None = None,
|
|
245
|
+
) -> Agreed | Declined:
|
|
246
|
+
"""Pay the agreement for h at url with signer, and return its receipt once recorded. atr_bytes are the ATR the
|
|
247
|
+
gate compared, for a pairing whose build reads them; inputs are the buyer's own chain values; ns is the namespace
|
|
248
|
+
of the pairing whose offer named the URL, which a refused URL's detail carries with the protocol package's code."""
|
|
249
|
+
if not is_https_link(url):
|
|
250
|
+
if ns is None:
|
|
251
|
+
return Declined("link-not-https", "The agreement URL is not an https URL.")
|
|
252
|
+
fault = "link-not-https" if is_other_scheme_link(url) else "legal-context-malformed"
|
|
253
|
+
return Declined("link-not-https", f"{ns}/{fault}")
|
|
254
|
+
|
|
255
|
+
unpaid = await _get(fetch, url, None, UNPAID_DEADLINE_S)
|
|
256
|
+
if isinstance(unpaid, Declined):
|
|
257
|
+
return unpaid
|
|
258
|
+
if isinstance(unpaid, _Unanswered):
|
|
259
|
+
return _failed("The agreement URL could not be reached.")
|
|
260
|
+
if unpaid.status == 200:
|
|
261
|
+
return _receipt(unpaid.body, h)
|
|
262
|
+
if unpaid.status == 202:
|
|
263
|
+
return Declined("agreement-pending", "An agreement payment for this ATR is already settling.")
|
|
264
|
+
if unpaid.status != 402:
|
|
265
|
+
return _failed(f"The agreement URL answered status {unpaid.status}.")
|
|
266
|
+
|
|
267
|
+
required = None if unpaid.payment_required is None else _from_base64_json(unpaid.payment_required)
|
|
268
|
+
if not isinstance(required, Mapping):
|
|
269
|
+
return _failed("The agreement URL answered 402 without a readable PAYMENT-REQUIRED.")
|
|
270
|
+
found = _agreement_pairing(required)
|
|
271
|
+
if isinstance(found, Declined):
|
|
272
|
+
return found
|
|
273
|
+
binding, read, option = found
|
|
274
|
+
limits = _bounds(option)
|
|
275
|
+
if limits is None:
|
|
276
|
+
return Declined("offer-unreadable", "x402/option-malformed")
|
|
277
|
+
if not hash_equals(read.h, h):
|
|
278
|
+
return Declined("hash-mismatch", "The agreement challenge advertises another ATR hash.")
|
|
279
|
+
|
|
280
|
+
paid = await _gate.pay(binding, read, required, signer, inputs if isinstance(inputs, Mapping) else {}, atr_bytes)
|
|
281
|
+
if isinstance(paid, Declined):
|
|
282
|
+
return paid
|
|
283
|
+
if paid is None:
|
|
284
|
+
return Declined("offer-unreadable", "The agreement payment gave nothing to sign.")
|
|
285
|
+
payment = _to_base64(paid.signed)
|
|
286
|
+
moved = Moved(paid.signed, atr_bytes, h)
|
|
287
|
+
pending = Declined("agreement-pending", "The agreement payment was sent and is not yet recorded.", moved)
|
|
288
|
+
|
|
289
|
+
request_s, exchange_s = limits
|
|
290
|
+
end = _clock() + exchange_s
|
|
291
|
+
while True:
|
|
292
|
+
remaining = end - _clock()
|
|
293
|
+
if remaining <= 0:
|
|
294
|
+
return pending
|
|
295
|
+
answer = await _get(fetch, url, payment, min(request_s, remaining))
|
|
296
|
+
if isinstance(answer, Declined):
|
|
297
|
+
return replace(answer, moved=moved)
|
|
298
|
+
wait = float(RETRY_DEFAULT_S)
|
|
299
|
+
if isinstance(answer, _Answer) and not _server_error(answer.status):
|
|
300
|
+
if answer.status == 200:
|
|
301
|
+
receipt = _receipt(answer.body, h)
|
|
302
|
+
return replace(receipt, moved=moved) if isinstance(receipt, Declined) else receipt
|
|
303
|
+
if answer.status != 202:
|
|
304
|
+
return _failed(f"The agreement URL answered status {answer.status} to the payment.", moved)
|
|
305
|
+
wait = float(_retry_seconds(answer.retry_after))
|
|
306
|
+
await _sleep(max(0.0, min(wait, end - _clock())))
|