Skip to content

Commit

Permalink
Update docs
Browse files Browse the repository at this point in the history
  • Loading branch information
ilikesymmetry committed Oct 17, 2024
1 parent 6937618 commit efe6e25
Show file tree
Hide file tree
Showing 5 changed files with 41 additions and 25 deletions.
48 changes: 31 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,25 +8,27 @@

### 1. Periphery addition to Coinbase Smart Wallet V1

While implementing this feature as a new V2 wallet implementation was tempting, we decided to leverage the modular owner system from [Smart Wallet V1](https://github.com/coinbase/smart-wallet) and avoid a hard upgrade. This helped reduce our launch timeline and also reduced the risk of introducing this unique account authentication paradigm.
While implementing this feature as a new V2 wallet implementation was tempting, we decided to leverage the modular owner system from [Smart Wallet V1](https://github.com/coinbase/smart-wallet) and avoid a hard upgrade.

### 2. Only Native and ERC-20 token support

Spend Permissions only support spending Native (e.g. ETH) and ERC-20 (e.g. USDC) tokens with a recurring allowance refresh. This enables use cases like subscriptins (e.g 10 USDC per month) out of the box and also can support apps that want to limit asking users for spend permissions every session.
Spend Permissions only supports spending Native (e.g. ETH) and ERC-20 (e.g. USDC) tokens on a recurring period. This enables use cases like subscriptions out of the box (e.g 10 USDC per month) and also can support apps that want to avoid asking users for spend permissions every session.

Compared to an approach that enables apps to make arbitrary external calls from user accounts, we consider this implementation safer given the tighter and fully-known scope of account control.
This approach does **not** enable apps to make arbitrary external calls from user accounts, improving security by having a tighter and fully-known scope of account control.

### 3. Spender-originated calls

Spend Permissions allow users to delegate token spending to a `spender` address, presumably controlled by the app. When an app wants to spend user tokens, it has `spender` call into the user account through a middleware contract, `SpendPermissionManager`, which validates the spend is within the approved allowance.
Spend Permissions allow users to delegate token spending to a `spender` address, presumably controlled by the app. When an app wants to spend user tokens, it calls into `SpendPermissionManager` from this `spender` address. `SpendPermissionManager` will then validate the spend is within the approved permission's allowance and calls into the user's account to transfer tokens.

Compared to an approach that uses the ERC-4337 EntryPoint to prompt external calls from user accounts, we consider this implementation safer given the avoided edge case of accounting for when ERC-4337 Paymasters spend user tokens.
This approach does **not** use the ERC-4337 EntryPoint to prompt external calls from user accounts, improving security by avoiding the possibility of ERC-4337 Paymasters spending users' tokens on gas fees.

## End-to-end Journey

### 1. App requests permissions from user (offchain)
### 1. App requests and user signs permissions (offchain)

Apps request spend permissions from users by sending an `eth_signTypedData` request containing the permission details.
Apps request spend permissions for users to sign by sending an `eth_signTypedData` RPC request containing the permission details.

Read more details [here](./docs/diagrams/signSpendPermission.md).

```mermaid
sequenceDiagram
Expand All @@ -52,31 +54,43 @@ sequenceDiagram

### 2. App approves and spends (onchain)

Apps approve their permission by calling `SpendPermissionManager.approveWithSignature` using the signature returned from the wallet when [requesting spend permissions](requestSpendPermission.md).
Spenders (apps) spend tokens by calling `SpendPermissionManager.spend` with their spend permission values, a recipient, and an amount of tokens to spend.

Spenders may want to batch this call with an additionally prepended call to [approve their permission via user signature](./approveWithSignature.md) or the convenience function `SpendPermissionManager.spendWithSignature`.

Read more details [here](./docs/diagrams/spend.md).

```mermaid
sequenceDiagram
autonumber
participant S as Spender
participant PM as Permission Manager
participant A as Account
participant F as Factory
participant ERC20
S->>PM: approveWithSignature
Note over PM: validate signature
opt if 6492 initCode
PM->>F: createAccount
F->>A: create2
opt
S->>PM: approveWithSignature
Note over PM: validate signature and store approval
end
S->>PM: spend
Note over PM: validate permission approved <br> and spend value within allowance
PM->>A: execute
Note over PM,A: transfer tokens
alt token is ERC-7528 address
A->>S: call{value}()
Note over A,S: transfer native token to spender
else else is ERC-20 contract
A->>ERC20: transfer(spender, value)
Note over A,ERC20: transfer ERC-20 to spender
end
PM->>A: isValidSignature
A-->>PM: EIP-1271 magic value
Note over PM: revert or store approval
```

### 3. User revokes permission (onchain)

Users can revoke permissions at any time by calling `SpendPermissionManager.revoke`, which can also be batched via `CoinbaseSmartWallet.executeBatch`.

Read more details [here](./docs/diagrams/revoke.md).

```mermaid
sequenceDiagram
autonumber
Expand Down
10 changes: 6 additions & 4 deletions docs/SpendPermissionAccounting.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,12 @@ This configuration would produce the following period-size ranges each with thei
When a new spend is attempted, the contract first determines what the current period range is. If the current time falls within the period of last stored use, we simply check if this new usage will exceed the allowance.

```
t = 0, spend = 25
new spend=25 @ t=0
period = [0, 99]
allowance = 0 + 25 = 25,
overspend = 25 > 100 = false
t = 10, spend = 25
new spend=25 @ t=50
period = [0, 99]
allowance = 25 + 25 = 50
overspend = 50 > 100 = false
Expand All @@ -55,11 +56,12 @@ overspend = 50 > 100 = false
If the current time exceeds the period of last stored use, that means we are in a new period and should reset the allowance to zero and then add our new attempted spend.

```
t = 0, spend = 25
new spend=25 @ t=0
period = [0, 99]
allowance = 0 + 25 = 25,
overspend = 25 > 100 = false
t = 110, spend = 25
new spend=25 @ t=150
period = [100, 199]
allowance = 0 + 25 = 25
overspend = 25 > 100 = false
Expand Down
2 changes: 1 addition & 1 deletion docs/diagrams/approve.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Approve Permissions

While the default experience is for apps to [request spend permissions](requestSpendPermission.md) and [approve with signatures](./approveWithSignature.md), it can also be valuable to approve permissions via direct calls to `SpendPermissionManager.approve`. For example, paying now to start a subscription and approving a permission to pay the same amount every month.
While the default experience is for apps to request the user [sign spend permissions](signSpendPermission.md) and [approve with signatures](./approveWithSignature.md), it can also be valuable to approve permissions via direct calls to `SpendPermissionManager.approve`. For example, paying now to start a subscription and approving a permission to pay the same amount every month.

```mermaid
sequenceDiagram
Expand Down
2 changes: 1 addition & 1 deletion docs/diagrams/approveWithSignature.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Approve Permission With Signature

Apps approve their permission by calling `SpendPermissionManager.approveWithSignature` using the signature returned from the wallet when [requesting spend permissions](requestSpendPermission.md).
Apps approve their permission by calling `SpendPermissionManager.approveWithSignature` using the signature returned from the wallet when [signing spend permissions](signSpendPermission.md).

If the signature is [ERC-6492](https://eips.ethereum.org/EIPS/eip-6492) formatted, `SpendPermissionManager` will automatically detect this and deploy the account on behalf of the app. Afterwards, it will call `isValidSignature` to verify the account signed the permission.

Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# Request Spend Permission
# Sign Spend Permission

Apps request spend permissions from users by sending an `eth_signTypedData` request containing the permission details.

Users are guided to sign the permission hash and add the `SpendPermissionManager` contract as an owner if it is not already.
Users are guided to sign the permission hash and add the `SpendPermissionManager` contract as an owner if it is not already. Signing to approve enables users to not spend gas on this action, offsetting this cost to the app.

If a users account is not yet deployed, but has the `SpendPermissionManager` as an initial owner in its `initCode`, the returned signature is formatted according to [ERC-6492](https://eips.ethereum.org/EIPS/eip-6492) with the `CoinbaseSmartWalletFactory` address and this `initCode`.

Expand Down

0 comments on commit efe6e25

Please sign in to comment.