Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions NOTICE
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,17 @@ distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

---

authCapture scheme:

The authCapture payment scheme and its TypeScript implementation in
@x402/evm were contributed by the x402r team. See proposal issue
#1011 and specification PR #1425. The implementation was developed
in https://github.com/BackTrackCo/x402r-scheme prior to upstreaming.

The implementation originated from the "x402-escrow" proposal by
Agentokratia in issue #834, published as @agentokratia/x402-escrow
on npm under the MIT License, and incorporates code from that
package.
2 changes: 2 additions & 0 deletions e2e/clients/axios/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
type UptoEvmSchemeOptions,
} from "@x402/evm/upto/client";
import { BatchSettlementEvmScheme } from "@x402/evm/batch-settlement/client";
import { AuthCaptureEvmScheme } from "@x402/evm/authCapture/client";
import { ExactEvmSchemeV1 } from "@x402/evm/v1";
import { toClientEvmSigner } from "@x402/evm";
import { ExactSvmScheme } from "@x402/svm/exact/client";
Expand Down Expand Up @@ -112,6 +113,7 @@ const client = new x402Client()
.register("eip155:*", new ExactEvmScheme(evmSigner, evmSchemeOptions))
.register("eip155:*", new UptoEvmClientScheme(evmSigner, uptoSchemeOptions))
.register("eip155:*", batchSettlementScheme)
.register("eip155:*", new AuthCaptureEvmScheme(evmSigner))
.registerV1("base-sepolia", new ExactEvmSchemeV1(evmSigner))
.registerV1("base", new ExactEvmSchemeV1(evmSigner))
.register("solana:*", new ExactSvmScheme(svmSigner))
Expand Down
3 changes: 2 additions & 1 deletion e2e/clients/axios/test.config.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@
"schemes": [
"exact",
"upto",
"batch-settlement"
"batch-settlement",
"authCapture"
],
"evm": {
"assetTransferMethods": [
Expand Down
2 changes: 2 additions & 0 deletions e2e/clients/fetch/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
type UptoEvmSchemeOptions,
} from "@x402/evm/upto/client";
import { BatchSettlementEvmScheme } from "@x402/evm/batch-settlement/client";
import { AuthCaptureEvmScheme } from "@x402/evm/authCapture/client";
import { ExactEvmSchemeV1 } from "@x402/evm/v1";
import { toClientEvmSigner } from "@x402/evm";
import { ExactSvmScheme } from "@x402/svm/exact/client";
Expand Down Expand Up @@ -111,6 +112,7 @@ const client = new x402Client()
.register("eip155:*", new ExactEvmScheme(evmSigner, evmSchemeOptions))
.register("eip155:*", new UptoEvmClientScheme(evmSigner, uptoSchemeOptions))
.register("eip155:*", batchSettlementScheme)
.register("eip155:*", new AuthCaptureEvmScheme(evmSigner))
.registerV1("base-sepolia", new ExactEvmSchemeV1(evmSigner))
.registerV1("base", new ExactEvmSchemeV1(evmSigner))
.register("solana:*", new ExactSvmScheme(svmSigner))
Expand Down
3 changes: 2 additions & 1 deletion e2e/clients/fetch/test.config.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@
"schemes": [
"exact",
"upto",
"batch-settlement"
"batch-settlement",
"authCapture"
],
"evm": {
"assetTransferMethods": [
Expand Down
2 changes: 2 additions & 0 deletions e2e/facilitators/typescript/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import {
VerifyResponse,
} from "@x402/core/types";
import { type AuthorizerSigner, toFacilitatorEvmSigner } from "@x402/evm";
import { AuthCaptureEvmScheme } from "@x402/evm/authCapture/facilitator";
import { BatchSettlementEvmScheme } from "@x402/evm/batch-settlement/facilitator";
import { ExactEvmScheme } from "@x402/evm/exact/facilitator";
import { UptoEvmScheme } from "@x402/evm/upto/facilitator";
Expand Down Expand Up @@ -422,6 +423,7 @@ facilitator
EVM_NETWORK as Network,
new BatchSettlementEvmScheme(evmSigner, authorizerSigner),
)
.register(EVM_NETWORK as Network, new AuthCaptureEvmScheme(evmSigner))
.registerV1(EVM_V1_NETWORKS as Network[], new ExactEvmSchemeV1(evmSigner))
.register(SVM_NETWORK as Network, new ExactSvmScheme(svmSigner))
.registerV1(SVM_V1_NETWORKS as Network[], new ExactSvmSchemeV1(svmSigner));
Expand Down
6 changes: 4 additions & 2 deletions e2e/facilitators/typescript/test.config.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@
"schemes": [
"exact",
"upto",
"batch-settlement"
"batch-settlement",
"authCapture"
],
"extensions": [
"bazaar",
Expand Down Expand Up @@ -49,7 +50,8 @@
"HEDERA_NETWORK",
"HEDERA_NODE_URL",
"STELLAR_NETWORK",
"EVM_RECEIVER_AUTHORIZER_PRIVATE_KEY"
"EVM_RECEIVER_AUTHORIZER_PRIVATE_KEY",
"EVM_AUTHCAPTURE_CAPTURE_AUTHORIZER"
]
}
}
71 changes: 71 additions & 0 deletions e2e/servers/express/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { ExactAvmScheme } from "@x402/avm/exact/server";
import { ExactEvmScheme } from "@x402/evm/exact/server";
import { UptoEvmScheme } from "@x402/evm/upto/server";
import { BatchSettlementEvmScheme } from "@x402/evm/batch-settlement/server";
import { AuthCaptureEvmScheme } from "@x402/evm/authCapture/server";
import { ExactSvmScheme } from "@x402/svm/exact/server";
import { ExactAptosScheme } from "@x402/aptos/exact/server";
import { ExactHederaScheme } from "@x402/hedera/exact/server";
Expand Down Expand Up @@ -94,6 +95,16 @@ server.register(
...(receiverAuthorizerSigner ? { receiverAuthorizerSigner } : {}),
}),
);
server.register("eip155:*", new AuthCaptureEvmScheme());

// captureAuthorizer for the authCapture scheme. Address allowed to call
// authorize/capture/void/refund/charge on AuthCaptureEscrow: either the
// facilitator's submitter EOA, or a smart contract that ultimately calls
// escrow as msg.sender (e.g., a refund-arbiter). Optional — when unset,
// authCapture routes are skipped.
const EVM_AUTHCAPTURE_CAPTURE_AUTHORIZER = process.env.EVM_AUTHCAPTURE_CAPTURE_AUTHORIZER as
| `0x${string}`
| undefined;
server.register("solana:*", new ExactSvmScheme());
if (APTOS_PAYEE_ADDRESS) {
server.register("aptos:*", new ExactAptosScheme());
Expand Down Expand Up @@ -261,6 +272,50 @@ app.use(
...declareErc20ApprovalGasSponsoringExtension(),
},
},
...(EVM_AUTHCAPTURE_CAPTURE_AUTHORIZER
? {
"GET /authCapture/evm/eip3009": {
accepts: {
payTo: EVM_PAYEE_ADDRESS,
scheme: "authCapture",
price: "$0.001",
network: EVM_NETWORK,
extra: {
captureAuthorizer: EVM_AUTHCAPTURE_CAPTURE_AUTHORIZER,
captureDeadline: Math.floor(Date.now() / 1000) + 3600,
refundDeadline: Math.floor(Date.now() / 1000) + 7200,
feeRecipient: EVM_PAYEE_ADDRESS,
minFeeBps: 0,
maxFeeBps: 100,
name: "USDC",
version: "2",
assetTransferMethod: "eip3009",
autoCapture: true,
},
},
},
"GET /authCapture/evm/permit2": {
accepts: {
payTo: EVM_PAYEE_ADDRESS,
scheme: "authCapture",
price: "$0.001",
network: EVM_NETWORK,
extra: {
captureAuthorizer: EVM_AUTHCAPTURE_CAPTURE_AUTHORIZER,
captureDeadline: Math.floor(Date.now() / 1000) + 3600,
refundDeadline: Math.floor(Date.now() / 1000) + 7200,
feeRecipient: EVM_PAYEE_ADDRESS,
minFeeBps: 0,
maxFeeBps: 100,
name: "USDC",
version: "2",
assetTransferMethod: "permit2",
autoCapture: true,
},
},
},
}
: {}),
"GET /exact/evm/eip3009": {
accepts: {
payTo: EVM_PAYEE_ADDRESS,
Expand Down Expand Up @@ -597,6 +652,22 @@ app.get("/batch-settlement/evm/permit2-erc20ApprovalGasSponsoring", (req, res) =
});
});

app.get("/authCapture/evm/eip3009", (req, res) => {
res.json({
message: "authCapture EIP-3009 endpoint accessed successfully",
timestamp: new Date().toISOString(),
method: "authCapture-eip3009",
});
});

app.get("/authCapture/evm/permit2", (req, res) => {
res.json({
message: "authCapture Permit2 endpoint accessed successfully",
timestamp: new Date().toISOString(),
method: "authCapture-permit2",
});
});

/**
* Protected endpoint - requires payment to access
*
Expand Down
21 changes: 21 additions & 0 deletions e2e/servers/express/test.config.json
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,27 @@
"coldstart": true
}
},
{
"path": "/authCapture/evm/eip3009",
"method": "GET",
"description": "authCapture EIP-3009 endpoint (autoCapture single-shot)",
"requiresPayment": true,
"protocolFamily": "evm",
"scheme": "authCapture",
"assetTransferMethod": "eip3009"
},
{
"path": "/authCapture/evm/permit2",
"method": "GET",
"description": "authCapture Permit2 endpoint (autoCapture single-shot, pre-approved Permit2)",
"requiresPayment": true,
"protocolFamily": "evm",
"scheme": "authCapture",
"assetTransferMethod": "permit2",
"schemeOptions": {
"permit2Direct": true
}
},
{
"path": "/exact/evm/permit2",
"method": "GET",
Expand Down
71 changes: 71 additions & 0 deletions e2e/servers/fastify/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { x402ResourceServer, HTTPFacilitatorClient } from "@x402/core/server";
import { ExactEvmScheme } from "@x402/evm/exact/server";
import { UptoEvmScheme } from "@x402/evm/upto/server";
import { BatchSettlementEvmScheme } from "@x402/evm/batch-settlement/server";
import { AuthCaptureEvmScheme } from "@x402/evm/authCapture/server";
import { ExactSvmScheme } from "@x402/svm/exact/server";
import { ExactAptosScheme } from "@x402/aptos/exact/server";
import { ExactHederaScheme } from "@x402/hedera/exact/server";
Expand Down Expand Up @@ -90,6 +91,16 @@ server.register(
...(receiverAuthorizerSigner ? { receiverAuthorizerSigner } : {}),
}),
);
server.register("eip155:*", new AuthCaptureEvmScheme());

// captureAuthorizer for the authCapture scheme. Address allowed to call
// authorize/capture/void/refund/charge on AuthCaptureEscrow: either the
// facilitator's submitter EOA, or a smart contract that ultimately calls
// escrow as msg.sender (e.g., a refund-arbiter). Optional — when unset,
// authCapture routes are skipped.
const EVM_AUTHCAPTURE_CAPTURE_AUTHORIZER = process.env.EVM_AUTHCAPTURE_CAPTURE_AUTHORIZER as
| `0x${string}`
| undefined;
server.register("solana:*", new ExactSvmScheme());
if (APTOS_PAYEE_ADDRESS) {
server.register("aptos:*", new ExactAptosScheme());
Expand Down Expand Up @@ -233,6 +244,50 @@ paymentMiddleware(
...declareErc20ApprovalGasSponsoringExtension(),
},
},
...(EVM_AUTHCAPTURE_CAPTURE_AUTHORIZER
? {
"GET /authCapture/evm/eip3009": {
accepts: {
payTo: EVM_PAYEE_ADDRESS,
scheme: "authCapture",
price: "$0.001",
network: EVM_NETWORK,
extra: {
captureAuthorizer: EVM_AUTHCAPTURE_CAPTURE_AUTHORIZER,
captureDeadline: Math.floor(Date.now() / 1000) + 3600,
refundDeadline: Math.floor(Date.now() / 1000) + 7200,
feeRecipient: EVM_PAYEE_ADDRESS,
minFeeBps: 0,
maxFeeBps: 100,
name: "USDC",
version: "2",
assetTransferMethod: "eip3009",
autoCapture: true,
},
},
},
"GET /authCapture/evm/permit2": {
accepts: {
payTo: EVM_PAYEE_ADDRESS,
scheme: "authCapture",
price: "$0.001",
network: EVM_NETWORK,
extra: {
captureAuthorizer: EVM_AUTHCAPTURE_CAPTURE_AUTHORIZER,
captureDeadline: Math.floor(Date.now() / 1000) + 3600,
refundDeadline: Math.floor(Date.now() / 1000) + 7200,
feeRecipient: EVM_PAYEE_ADDRESS,
minFeeBps: 0,
maxFeeBps: 100,
name: "USDC",
version: "2",
assetTransferMethod: "permit2",
autoCapture: true,
},
},
},
}
: {}),
"GET /exact/evm/eip3009": {
accepts: {
payTo: EVM_PAYEE_ADDRESS,
Expand Down Expand Up @@ -551,6 +606,22 @@ app.get("/batch-settlement/evm/permit2-erc20ApprovalGasSponsoring", async () =>
};
});

app.get("/authCapture/evm/eip3009", async () => {
return {
message: "authCapture EIP-3009 endpoint accessed successfully",
timestamp: new Date().toISOString(),
method: "authCapture-eip3009",
};
});

app.get("/authCapture/evm/permit2", async () => {
return {
message: "authCapture Permit2 endpoint accessed successfully",
timestamp: new Date().toISOString(),
method: "authCapture-permit2",
};
});

/**
* Protected endpoint - requires payment to access
*
Expand Down
21 changes: 21 additions & 0 deletions e2e/servers/fastify/test.config.json
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,27 @@
"coldstart": true
}
},
{
"path": "/authCapture/evm/eip3009",
"method": "GET",
"description": "authCapture EIP-3009 endpoint (autoCapture single-shot)",
"requiresPayment": true,
"protocolFamily": "evm",
"scheme": "authCapture",
"assetTransferMethod": "eip3009"
},
{
"path": "/authCapture/evm/permit2",
"method": "GET",
"description": "authCapture Permit2 endpoint (autoCapture single-shot, pre-approved Permit2)",
"requiresPayment": true,
"protocolFamily": "evm",
"scheme": "authCapture",
"assetTransferMethod": "permit2",
"schemeOptions": {
"permit2Direct": true
}
},
{
"path": "/exact/evm/permit2",
"method": "GET",
Expand Down
Loading
Loading