Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(delegated payments): init managing and using delegate payment approvals PE-6754 #191

Merged
merged 29 commits into from
Oct 31, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
e565bf7
chore: adjust sol types PE-6754
fedellen Oct 16, 2024
953648e
feat(delegated payments): add paid-by headers for uploads when applic…
fedellen Oct 16, 2024
1047762
feat(delegated payments): init logic for create-approval PE-6754
fedellen Oct 16, 2024
f2d26da
feat(delegated payments): add revoke approvals to SDK and CLI PE-6754
fedellen Oct 16, 2024
baec107
feat(delegated payments): extend turbo.getBalance method to include a…
fedellen Oct 21, 2024
f6101d9
test(delegated payments): init docker integration tests for delegated…
fedellen Oct 23, 2024
96d4a32
feat(delegated payments): use any approvals first by default on CLI P…
fedellen Oct 24, 2024
1cccdb7
docs(delegated payments): add README for paid-by PE-6754
fedellen Oct 24, 2024
669dfca
feat(delegated payments): display approvals if they exist on `balance…
fedellen Oct 24, 2024
35f00e1
docs(delegated payments): add README for create and revoke approval c…
fedellen Oct 24, 2024
8dc4ec8
refactor: clean-up whitespace PE-6754
fedellen Oct 24, 2024
eaabd39
Merge branch 'alpha' into PE-6754-delegated-payments
fedellen Oct 24, 2024
33da73d
feat(delegated payments): push created/revoked approvals into upload …
fedellen Oct 24, 2024
925ee40
docs(delegated payments): add README for create/revoke/get approvals …
fedellen Oct 24, 2024
2da65da
docs(delegated payments): add README ToC for get approvals PE-6754
fedellen Oct 25, 2024
049e990
refactor(delegated payments): gracefully handle recievedApprovals in …
fedellen Oct 25, 2024
2e2bb83
refactor(delegated payments): excise rogue console.log PE-6754
fedellen Oct 25, 2024
7d1cc0b
refactor(delegated payments): excise rogue console.log PE-6754
fedellen Oct 25, 2024
e1c5fb5
refactor(delegated payments): dedupe on paying addresses for "any" pa…
fedellen Oct 25, 2024
79fe7a0
feat: add cli helper for --local development endpoints PE-6754
fedellen Oct 25, 2024
ee44ef6
feat(delegated payments): add list-approvals command rather than over…
fedellen Oct 25, 2024
17e215f
test(delegated payments): update error msg expectation PE-6754
fedellen Oct 28, 2024
37357ab
test(delegated payments): improve coverage on new flows PE-6754
fedellen Oct 28, 2024
cee5d64
refactor: use safer bignumber.dividedBy for crypto fund confirmation …
fedellen Oct 28, 2024
bb30b13
refactor: remove potential decimals with toFixed for approved winc am…
fedellen Oct 28, 2024
e2390b4
test(delegated payments): improve coverage on get approvals PE-6754
fedellen Oct 28, 2024
ba7d86b
refactor: adjust revoke-approvals cli command output PE-6754
fedellen Oct 28, 2024
a6eedd2
refactor: excise extra whitespace in list-aprovals command message PE…
fedellen Oct 28, 2024
b060b78
docs(delegated payments): add README section for list approvals PE-6754
fedellen Oct 30, 2024
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
96 changes: 95 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,9 @@ Welcome to the `@ardrive/turbo-sdk`! This SDK provides functionality for interac
- [Polygon (POL / MATIC) Crypto Top Up](#polygon-pol--matic-crypto-top-up)
- [Solana (SOL) Crypto Top Up](#solana-sol-crypto-top-up)
- [KYVE Crypto Top Up](#kyve-crypto-top-up)
- [`createDelegatedPaymentApproval({ approvedAddress, approvedWincAmount, expiresBySeconds })`](#createdelegatedpaymentapproval-approvedaddress-approvedwincamount-expiresbyseconds-)
- [`revokeDelegatedPaymentApprovals({ approvedAddress })`](#revokedelegatedpaymentapprovals-approvedaddress-)
- [`getDelegatedPaymentApprovals({ userAddress })`](#getdelegatedpaymentapprovals-useraddress-)
- [CLI](#cli)
- [Install CLI](#install-cli)
- [CLI Usage](#cli-usage)
Expand All @@ -76,6 +79,9 @@ Welcome to the `@ardrive/turbo-sdk`! This SDK provides functionality for interac
- [`upload-folder`](#upload-folder)
- [`upload-file`](#upload-file)
- [`price`](#price)
- [`create-approval`](#create-approval)
- [`revoke-approvals`](#revoke-approvals)
- [`list-approvals`](#list-approvals)
- [Developers](#developers)
- [Requirements](#requirements)
- [Setup & Build](#setup--build)
Expand Down Expand Up @@ -677,6 +683,40 @@ const { winc, status, id, ...fundResult } = await turbo.topUpWithTokens({
});
```

#### `createDelegatedPaymentApproval({ approvedAddress, approvedWincAmount, expiresBySeconds })`

Creates a delegated payment approval from the connected wallet to the provided native address and approved winc amount. This action will create a data item for the approval

```typescript
const { approvalDataItemId, approvedWincAmount } =
await turbo.createDelegatedPaymentApproval({
approvedAddress: '2cor...VUa',
approvedWincAmount: 0.08315565032,
expiresBySeconds: 3600,
});
```

#### `revokeDelegatedPaymentApprovals({ approvedAddress })`

Revokes all delegated payment approvals from the connected wallet to the provided native address.

```typescript
const revokedApprovals = await turbo.revokeDelegatePaymentApprovals({
approvedAddress: '2cor...VUa',
});
```

#### `getDelegatedPaymentApprovals({ userAddress })`

Returns all delegated payment approvals from the connected wallet or the provided native address.

```typescript
const { givenApprovals, receivedApprovals } =
await turbo.getDelegatedPaymentApprovals({
userAddress: '2cor...VUa',
});
```

## CLI

### Install CLI
Expand Down Expand Up @@ -723,6 +763,8 @@ npx turbo --help

#### Options

Global options:

- `-V, --version` - output the version number
- `-h, --help` - display help for command
- `--dev` - Enable development endpoints (default: false)
Expand All @@ -731,10 +773,18 @@ npx turbo --help
- `--payment-url <url>` - Set a custom payment service URL
- `-t, --token <token>` - Token type for the command or connected wallet (default: "arweave")

Wallet options:

- `-w, --wallet-file <filePath>` - Wallet file to use with the action. Formats accepted: JWK.json, KYVE, ETH, or POL private key as a string, or SOL Secret Key as a Uint8Array
- `-m, --mnemonic <phrase>` - Mnemonic to use with the action (KYVE only)
- `-p, --private-key <key>` - Private key to use with the action

Upload options:

- `--paid-by <paidBy...>` - An array of native addresses to pay for the upload
- `--ignore-approvals` - The CLI will normally use any delegated payment approvals for the upload. This flag will ignore any approvals and only use the connected wallet's balance for upload payment. Default: false
- `--use-signer-balance-first` - Use the connected wallet's balance before using any delegated payment approvals for the upload. Default: false

#### Commands

##### `balance`
Expand Down Expand Up @@ -820,7 +870,7 @@ Command Options:
e.g:

```shell
turbo upload-file --file-path '../path/to/my/file.txt' --token ethereum --wallet-file ../path/to/eth/private/key.txt
turbo upload-file --file-path '../path/to/my/file.txt' --token ethereum --wallet-file ../path/to/eth/private/key.txt --paid-by '0x...address' '0x...another-address'
```

##### `price`
Expand All @@ -846,6 +896,50 @@ turbo price --value 1024 --type bytes
turbo price --value 1.1 --type arweave
```

##### `create-approval`

Create a delegated payment approval from the connected wallet to the provided native address and approved winc amount.

Command Options:

- `-a, --address <nativeAddress>` - Native address to that will receive the delegated payment approval
- `-v, --value <value>` - Value of winc to create delegated payment approval for
- `-e, --expires-by-seconds <seconds>` - Expiry time in seconds for the delegated payment approval

e.g:

```shell
turbo create-approval --address 2cor...VUa --value 0.083155650320 --wallet-file ../path/to/my/wallet --expires-by-seconds 3600
```

##### `revoke-approvals`

Revoke all delegated payment approvals from the connected wallet to the provided native address.

Command Options:

- `-a, --address <nativeAddress>` - Native address to revoke delegated payment approvals for

e.g:

```shell
turbo revoke-approvals --wallet-file ../path/to/my/wallet
```

##### `list-approvals`

List all given and received delegated payment approvals from the connected wallet or the provided native address.

Command Options:

- `-a, --address <nativeAddress>` - Native address to list delegated payment approvals for

e.g:

```shell
turbo list-approvals --address 2cor...VUa --wallet-file ../path/to/my/wallet
```

## Developers

### Requirements
Expand Down
6 changes: 4 additions & 2 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
version: '3.0'

services:
arlocal:
image: textury/arlocal:v1.1.66
Expand All @@ -25,6 +23,8 @@ services:
# - '8545:8545'

upload-service:
# build:
# context: ../upload-service
image: ghcr.io/ardriveapp/upload-service:latest
ports:
- '3000:3000'
Expand Down Expand Up @@ -112,6 +112,8 @@ services:
start_period: 10s

payment-service:
# build:
# context: ../payment-service
image: ghcr.io/ardriveapp/payment-service:latest
ports:
- '4000:4000'
Expand Down
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -69,16 +69,16 @@
"example:web": "http-server --port 8080 --host -o examples/web",
"example:ts:esm": "cd examples/typescript/esm && yarn && yarn test",
"example:ts:cjs": "cd examples/typescript/cjs && yarn && yarn test",
"docker:up": "docker compose up --quiet-pull --pull always -d",
"docker:up": "docker compose up --quiet-pull -d",
"docker:down": "docker compose down -v",
"docs": "markdown-toc-gen insert README.md"
},
"dependencies": {
"@dha-team/arbundles": "^1.0.1",
"@cosmjs/amino": "^0.32.4",
"@cosmjs/crypto": "^0.32.4",
"@cosmjs/encoding": "^0.32.4",
"@cosmjs/proto-signing": "^0.32.4",
"@dha-team/arbundles": "^1.0.1",
"@ethersproject/signing-key": "^5.7.0",
"@kyvejs/sdk": "^1.3.3",
"@solana/web3.js": "^1.91.7",
Expand Down Expand Up @@ -116,6 +116,7 @@
"@typescript-eslint/parser": "^6.4.0",
"c8": "^8.0.1",
"chai": "^4.3.7",
"dotenv": "^16.4.5",
"dotenv-cli": "^7.4.1",
"esbuild": "^0.19.2",
"esbuild-plugin-polyfill-node": "^0.3.0",
Expand Down
37 changes: 37 additions & 0 deletions src/cli/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import { Command, program } from 'commander';

import { version } from '../version.js';
import { createApproval } from './commands/createApproval.js';
import {
balance,
cryptoFund,
Expand All @@ -28,9 +29,14 @@ import {
uploadFile,
uploadFolder,
} from './commands/index.js';
import { listApprovals } from './commands/listApprovals.js';
import { revokeApprovals } from './commands/revokeApprovals.js';
import {
createApprovalOptions,
globalOptions,
listApprovalsOptions,
optionMap,
revokeApprovalsOptions,
uploadFileOptions,
uploadFolderOptions,
walletOptions,
Expand Down Expand Up @@ -93,6 +99,37 @@ applyOptions(
await runCommand(command, price);
});

applyOptions(
program
.command('create-approval')
.description('Create a Turbo delegated payment approval'),
createApprovalOptions,
).action(async (_commandOptions, command: Command) => {
await runCommand(command, createApproval);
});

applyOptions(
program
.command('revoke-approvals')
.description(
'Revokes all Turbo delegated payment approvals for given address',
),
revokeApprovalsOptions,
).action(async (_commandOptions, command: Command) => {
await runCommand(command, revokeApprovals);
});

applyOptions(
program
.command('list-approvals')
.description(
'Lists all Turbo delegated payment approvals for given address or wallet',
),
listApprovalsOptions,
).action(async (_commandOptions, command: Command) => {
await runCommand(command, listApprovals);
});

if (
process.argv[1].includes('bin/turbo') || // Running from global .bin
process.argv[1].includes('cli/cli') // Running from source
Expand Down
55 changes: 31 additions & 24 deletions src/cli/commands/balance.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,40 +13,47 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { BigNumber } from 'bignumber.js';

import { TurboFactory } from '../../node/factory.js';
import { wincPerCredit } from '../constants.js';
import { AddressOptions } from '../types.js';
import { addressOrPrivateKeyFromOptions, configFromOptions } from '../utils.js';

export async function balance(options: AddressOptions) {
const config = configFromOptions(options);

const { address, privateKey } = await addressOrPrivateKeyFromOptions(options);

if (address !== undefined) {
const turbo = TurboFactory.unauthenticated(config);
const { winc } = await turbo.getBalance(address);

console.log(
`Turbo Balance for Native Address "${address}"\nCredits: ${
+winc / 1_000_000_000_000
}`,
);
return;
}

if (privateKey === undefined) {
throw new Error('Must provide an (--address) or use a valid wallet');
}

const turbo = TurboFactory.authenticated({
...config,
privateKey,
});
const { effectiveBalance, nativeAddress, winc, controlledWinc } =
await (async () => {
if (address !== undefined) {
return {
...(await TurboFactory.unauthenticated(config).getBalance(address)),
nativeAddress: address,
};
}
if (privateKey === undefined) {
throw new Error('Must provide an (--address) or use a valid wallet');
}
const turbo = TurboFactory.authenticated({
...config,
privateKey,
});
return {
...(await turbo.getBalance()),
nativeAddress: await turbo.signer.getNativeAddress(),
};
})();

const { winc } = await turbo.getBalance();
console.log(
`Turbo Balance for Wallet Address "${await turbo.signer.getNativeAddress()}"\nCredits: ${
+winc / 1_000_000_000_000
`Turbo Balance for Native Address "${nativeAddress}"\nEffective Credits: ${
+effectiveBalance / wincPerCredit
}${
winc === controlledWinc
? ''
: `\nCredits Shared to Other Wallets: ${BigNumber(controlledWinc)
.minus(winc)
.div(wincPerCredit)}`
}`,
);
}
52 changes: 52 additions & 0 deletions src/cli/commands/createApproval.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/**
* Copyright (C) 2022-2024 Permanent Data Solutions, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* 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.
*/
import { BigNumber } from 'bignumber.js';

import { CreateApprovalOptions } from '../types.js';
import { turboFromOptions } from '../utils.js';

export async function createApproval(
options: CreateApprovalOptions,
): Promise<void> {
const {
address: approvedAddress,
value: creditAmount,
expiresBySeconds,
} = options;
if (approvedAddress === undefined) {
throw new Error(
'Must provide an approved --address to create approval for',
);
}
if (creditAmount === undefined) {
throw new Error('Must provide a credit --value to create approval for');
}

const turbo = await turboFromOptions(options);

const approvedWincAmount = new BigNumber(creditAmount)
.shiftedBy(12)
.toFixed(0);
const result = await turbo.createDelegatedPaymentApproval({
approvedAddress,
approvedWincAmount,
expiresBySeconds,
});

console.log(
JSON.stringify({ message: 'Created approval:', ...result }, null, 2),
);
}
Loading
Loading