Skip to content

Commit

Permalink
fmt
Browse files Browse the repository at this point in the history
  • Loading branch information
bitdivine committed Oct 1, 2024
1 parent cf0deb7 commit 46147c5
Show file tree
Hide file tree
Showing 14 changed files with 983 additions and 966 deletions.
42 changes: 28 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,44 +4,55 @@
# Get paid for your API.

## TLDR
**`papi` adds a payment gateway to an API. Choose which cryptocurrencies you would like to be paid in, and how much each API call should cost, and the `papi` integration will handle the rest.**

**`papi` adds a payment gateway to an API. Choose which cryptocurrencies you would like to be paid in, and how much each API call should cost, and the `papi` integration will handle the rest.**

## Details

### Choice of cryptocurrency

The following cryptocurrencies are supported:

| Name | Token | Comment |
| ---- | ----- | ------- |
| Bitcoin | ckBTC | High speed, low transaction costs are enabled via decentralized chain keys. |
| Ethereum | ckETH | High speed, low transaction costs are enabled via decentralized chain keys. |
| US Dollar | ckUSDC | High speed, low transaction costs are enabled via decentralized chain keys. |
| ICP Cycles | XDR | The native utility token of the Internet Computer, tied in price to the IMF XDR basket of currencies. |
| ICP | ICP | The governance token of the Internet Computer. |
And many more. All tokens that support the ICRC-2 standard can be used.
| Name | Token | Comment |
| ---------- | ------ | ----------------------------------------------------------------------------------------------------- |
| Bitcoin | ckBTC | High speed, low transaction costs are enabled via decentralized chain keys. |
| Ethereum | ckETH | High speed, low transaction costs are enabled via decentralized chain keys. |
| US Dollar | ckUSDC | High speed, low transaction costs are enabled via decentralized chain keys. |
| ICP Cycles | XDR | The native utility token of the Internet Computer, tied in price to the IMF XDR basket of currencies. |
| ICP | ICP | The governance token of the Internet Computer. |

And many more. All tokens that support the ICRC-2 standard can be used.

### Chain keys: ckBTC, ckETH, ckUSDC, ...
APIs require high speed, low latency and low transaction fees. Otherwise the user experience will be terrible. Chain Key provides a standard, cryptocurrency-agnostic, decentralized way of delivering these necessary properties. If you are excited by technical details, you will be glad to know that Chain Key Technology enables making L2s on the ICP with threshold keys. ICP provides the high performance and the threshold keys provide the foundation for making the L2 decentralized.

APIs require high speed, low latency and low transaction fees. Otherwise the user experience will be terrible. Chain Key provides a standard, cryptocurrency-agnostic, decentralized way of delivering these necessary properties. If you are excited by technical details, you will be glad to know that Chain Key Technology enables making L2s on the ICP with threshold keys. ICP provides the high performance and the threshold keys provide the foundation for making the L2 decentralized.

### Technical Integration
You will need to define a default currency for payment and annotate API methods with how much you would like to charge for each call. When a customer makes an API call, the customer's default account will be charged for the API call. The customer will have to authorize the payment in advance using an ICRC-2 approval. In the case of payment with ICP cycles, payment MAY also be attached directly to the API call.

This flow can be customized by providing explicit payment parameters. For every API method you have, another will be added with the `paid_` prefix and the payment parameter. For example, if you have an API method `is_prime(x: u32) -> bool`, a method will be added `paid_is_prime(payment_details, u32) -> Result<bool, PaymentError>`. The default flow has the advantage that you do not need to alter your API in any way. With this explicit payment mechanism you have more options, such as support for multiple currencies and payment by accounts other than the caller.
You will need to define a default currency for payment and annotate API methods with how much you would like to charge for each call. When a customer makes an API call, the customer's default account will be charged for the API call. The customer will have to authorize the payment in advance using an ICRC-2 approval. In the case of payment with ICP cycles, payment MAY also be attached directly to the API call.

Optionally, pre-payment is also supported. In this case, the `papi` library will need to store customer credits in stable memory and you will need to set the duration for which pre-paid credits are valid.
This flow can be customized by providing explicit payment parameters. For every API method you have, another will be added with the `paid_` prefix and the payment parameter. For example, if you have an API method `is_prime(x: u32) -> bool`, a method will be added `paid_is_prime(payment_details, u32) -> Result<bool, PaymentError>`. The default flow has the advantage that you do not need to alter your API in any way. With this explicit payment mechanism you have more options, such as support for multiple currencies and payment by accounts other than the caller.

Optionally, pre-payment is also supported. In this case, the `papi` library will need to store customer credits in stable memory and you will need to set the duration for which pre-paid credits are valid.

#### Examples

This API requires payment in cycles:

```
#[paid_api(ledger="cycles_ledger", fee="10000")]
#[update]
is_prime(x: u32) -> bool {...}
```

A user MAY pay by attaching cycles directly to API call:

```
dfx canister call "$MATH_CANISTER_ID" --with-cycles 10000 is_prime '(1234567)'
```

A user MAY also pre-approve payment, then make the call:

```
dfx canister call $CYCLES_LEDGER icrc2_approve '
record {
Expand All @@ -54,7 +65,9 @@ dfx canister call $CYCLES_LEDGER icrc2_approve '
dfx canister call "$MATH_CANISTER_ID" is_prime '(1234567)'
```
Finally, there are complex use cases where another user pays on behalf of the caller. In this case, the payer needs to set aside some funds for the caller in a sub-account and approve the payment. The funds can be used only by that caller:

Finally, there are complex use cases where another user pays on behalf of the caller. In this case, the payer needs to set aside some funds for the caller in a sub-account and approve the payment. The funds can be used only by that caller:

```
# Payer:
## Add funds to a subaccount for the caller:
Expand All @@ -77,6 +90,7 @@ dfx canister call $CYCLES_LEDGER icrc2_approve '
PAYER_ACCOUNT="$(dfx ledger account-id --of-principal "$PAYER")"
dfx canister call "$MATH_CANISTER_ID" paid_is_prime '(record{account="'$PAYER_ACCOUNT'"}, 1234567)'
```

Your canister will retrieve the pre-approved payment before proceeding with the API call.

## Detailed design
Expand Down
5 changes: 3 additions & 2 deletions USAGE.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@
## Creating a paid API

### Accept many payment types
- In your canister, you need to decide which payment types you wish to accept. In [this example](./src/example/paid_service/src/state.rs) a `PAYMENT_GUARD` is defined that accepts a variety of payment options.
- In the API methods, you need to [deduct payment](./src/example/paid_service/src/lib.rs) before doing work.

- In your canister, you need to decide which payment types you wish to accept. In [this example](./src/example/paid_service/src/state.rs) a `PAYMENT_GUARD` is defined that accepts a variety of payment options.
- In the API methods, you need to [deduct payment](./src/example/paid_service/src/lib.rs) before doing work.
90 changes: 45 additions & 45 deletions dev-tools.json
Original file line number Diff line number Diff line change
@@ -1,47 +1,47 @@
{
"rustup": {
"method": "curl",
"version": "1.25.2",
"url": "https://raw.githubusercontent.com/rust-lang/rustup/1.25.2/rustup-init.sh",
"pipe": [["sh"]]
},
"n": {
"method": "curl",
"version": "v9.0.1",
"url": "https://github.com/tj/n/blob/v9.0.1/bin/n"
},
"shfmt": {
"method": "go",
"version": "v3.5.1",
"source": "mvdan.cc/sh/v3/cmd/shfmt"
},
"yq": {
"method": "go",
"version": "v4.33.3",
"source": "github.com/mikefarah/yq/v4"
},
"node": {
"method": "n",
"version": "18.14.2"
},
"cargo-binstall": {
"method": "sh",
"version": "1.7.4"
},
"cargo-audit": {
"method": "cargo-binstall",
"version": "0.13.1"
},
"cargo-sort": {
"method": "cargo-binstall",
"version": "1.0.9"
},
"candid-extractor": {
"method": "cargo-binstall",
"version": "0.1.4"
},
"cargo-tarpaulin": {
"method": "cargo-binstall",
"version": "0.26.1"
}
"rustup": {
"method": "curl",
"version": "1.25.2",
"url": "https://raw.githubusercontent.com/rust-lang/rustup/1.25.2/rustup-init.sh",
"pipe": [["sh"]]
},
"n": {
"method": "curl",
"version": "v9.0.1",
"url": "https://github.com/tj/n/blob/v9.0.1/bin/n"
},
"shfmt": {
"method": "go",
"version": "v3.5.1",
"source": "mvdan.cc/sh/v3/cmd/shfmt"
},
"yq": {
"method": "go",
"version": "v4.33.3",
"source": "github.com/mikefarah/yq/v4"
},
"node": {
"method": "n",
"version": "18.14.2"
},
"cargo-binstall": {
"method": "sh",
"version": "1.7.4"
},
"cargo-audit": {
"method": "cargo-binstall",
"version": "0.13.1"
},
"cargo-sort": {
"method": "cargo-binstall",
"version": "1.0.9"
},
"candid-extractor": {
"method": "cargo-binstall",
"version": "0.1.4"
},
"cargo-tarpaulin": {
"method": "cargo-binstall",
"version": "0.26.1"
}
}
88 changes: 44 additions & 44 deletions dfx.json
Original file line number Diff line number Diff line change
@@ -1,46 +1,46 @@
{
"dfx": "0.23.0",
"canisters": {
"example_paid_service": {
"candid": "src/example/paid_service/example-paid-service.did",
"package": "example_paid_service",
"type": "rust",
"optimize": "cycles",
"gzip": true,
"dependencies": ["cycles_ledger"]
},
"example_app_backend": {
"candid": "src/example/app_backend/example_app_backend.did",
"package": "example_app_backend",
"type": "rust"
},
"cycles_ledger": {
"type": "custom",
"candid": "https://github.com/dfinity/cycles-ledger/releases/download/cycles-ledger-v1.0.1/cycles-ledger.did",
"wasm": "https://github.com/dfinity/cycles-ledger/releases/download/cycles-ledger-v1.0.1/cycles-ledger.wasm.gz",
"init_arg": "( variant { Init = record { index_id = null; max_blocks_per_request = 9_999 : nat64 }},)",
"specified_id": "um5iw-rqaaa-aaaaq-qaaba-cai",
"remote": {
"id": {
"ic": "um5iw-rqaaa-aaaaq-qaaba-cai"
}
}
},
"cycles_depositor": {
"dependencies": ["cycles_ledger"],
"type": "custom",
"build": "scripts/build.cycles_depositor.sh",
"init_arg_file": "out/cycles_depositor.args.did",
"wasm": "out/cycles_depositor.wasm.gz",
"candid": "out/cycles_depositor.did"
}
},
"defaults": {
"build": {
"args": "",
"packtool": ""
}
},
"output_env_file": ".env",
"version": 1
"dfx": "0.23.0",
"canisters": {
"example_paid_service": {
"candid": "src/example/paid_service/example-paid-service.did",
"package": "example_paid_service",
"type": "rust",
"optimize": "cycles",
"gzip": true,
"dependencies": ["cycles_ledger"]
},
"example_app_backend": {
"candid": "src/example/app_backend/example_app_backend.did",
"package": "example_app_backend",
"type": "rust"
},
"cycles_ledger": {
"type": "custom",
"candid": "https://github.com/dfinity/cycles-ledger/releases/download/cycles-ledger-v1.0.1/cycles-ledger.did",
"wasm": "https://github.com/dfinity/cycles-ledger/releases/download/cycles-ledger-v1.0.1/cycles-ledger.wasm.gz",
"init_arg": "( variant { Init = record { index_id = null; max_blocks_per_request = 9_999 : nat64 }},)",
"specified_id": "um5iw-rqaaa-aaaaq-qaaba-cai",
"remote": {
"id": {
"ic": "um5iw-rqaaa-aaaaq-qaaba-cai"
}
}
},
"cycles_depositor": {
"dependencies": ["cycles_ledger"],
"type": "custom",
"build": "scripts/build.cycles_depositor.sh",
"init_arg_file": "out/cycles_depositor.args.did",
"wasm": "out/cycles_depositor.wasm.gz",
"candid": "out/cycles_depositor.did"
}
},
"defaults": {
"build": {
"args": "",
"packtool": ""
}
},
"output_env_file": ".env",
"version": 1
}
Loading

0 comments on commit 46147c5

Please sign in to comment.