Skip to content

Commit 74c8a47

Browse files
authored
Merge pull request #61 from Convex-Dev/develop
Merge latest changes
2 parents 5994040 + 7b9042d commit 74c8a47

File tree

21 files changed

+1164
-183
lines changed

21 files changed

+1164
-183
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -23,3 +23,4 @@ yarn-error.log*
2323
/.project
2424
/.settings/
2525

26+
.lsp/.cache

.lsp/.cache/db.transit.json

-1
This file was deleted.

docs/cad/000_principles/README.md

+10
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,16 @@ It is therefore necessary to place a bound on the size of resources used. This i
2727

2828
Where input to Convex may be effectively unbounded (e.g. the size of data structures such as Vectors), implementations MUST NOT attempt O(n) or greater operations on such structures unless these operations are protected by resource constraints (e.g. accounting for juice costs, memory allowances).
2929

30+
### Conflict-free replication
31+
32+
We have designed lattice technology so that it can operate as a conflict-free replicated data type: this enables scalable systems without the need for locking and synchronisation between distributed processes. Arguably this is the *only* practical way to achieve decentralised consensus at the scales we envisage.
33+
34+
This places some restrictions on technical implementation:
35+
- Message handling should be idempotent, i.e. repeated receipt of identical messages should have no effect (and consume minimal resources)
36+
- Data structures must be designed for efficient CRDT merge operations
37+
- Systems must be designed to operate on the latest concurrent immutable state, with the knowledge that this state may change as it converges towards eventual consistency
38+
- Situations which are ordering-dependent must use CPoS to reach consensus on ordering (this mostly applies to the ordering of Convex transactions at present, but may apply to other lattice merge operations in future)
39+
3040
## General Design Philosophy
3141

3242
### Security First

docs/cad/019_assets/README.md

+109-19
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,11 @@ The Convex Asset Model is a universal system for expressing and controlling digi
1010

1111
A key design goal is therefore that the API is universal and extensible, in the sense that it can be used to handle a diverse ecosystem of digital assets, including asset types that have not yet been invented. By way of example, it should be possible to use the same API to transfer a quantity of a fungible token:
1212

13-
`(asset/transfer [currency.USD 10000] destination-address)`
13+
`(asset/transfer destination-address [currency.USD 10000] )`
1414

1515
As it is to transfer a set of numbered NFTs:
1616

17-
`(asset/transfer [asset.nfts #{101 102 105}] destination-address)`
17+
`(asset/transfer destination-address [asset.nfts #{101 102 105}] )`
1818

1919
So... why is this important?
2020

@@ -47,13 +47,13 @@ Examples:
4747

4848
### Asset Implementation
4949

50-
Asset logic MUST be implemented by an Actor on Convex. This actor may be referred to as the "asset implementation".
50+
Asset logic MUST be implemented by an actor on Convex. This actor may be referred to as the "asset implementation" or "asset actor".
5151

5252
An asset MAY map one-to-one to an actor, however a single actor MAY implement multiple assets. This allowance is primarily for efficiency reasons: if many assets share the same on-chain logic, it makes sense for a single actor to implement them all rather than deploying new actors for each one.
5353

5454
The use of an actor to provide the asset implementation is important for two reasons:
5555

56-
- It allows for the development of new types of compatible assets: these simply need to provide a new implementation actor and they can be used according to the standard asset model, often without needing to change existing code.
56+
- It allows for the development of new types of compatible assets: these simply need to provide a new implementation and they can be used according to the standard CAD19 asset model, often without needing to change existing code.
5757
- Actors allow for trusted code execution and governance, providing assurance that digital assets will behave correctly and not present unacceptable security risks
5858

5959
### Asset Path
@@ -62,14 +62,14 @@ An asset path is a descriptor that identifies an asset. Asset paths are importan
6262

6363
An asset path MUST be either:
6464

65-
- The Address of the actor that provides the asset implementation - e.g. - `#1234` is a valid asset path referring to the asset implemented by the actor at the Address `#1234`
66-
- A Vector where the first element is the Address of the actor, and the remainder of the Vector is interpreted by that Actor on an implementation defined basis. e.g. `#[2345 :foo :bar]`
65+
- The address of the actor that provides the asset implementation - e.g. - `#1234` is a valid asset path referring to the asset implemented by the actor at the address `#1234`
66+
- A vector where the first element is the address of the actor, and the second element of the vector is a scoped value interpreted by that actor on an implementation defined basis. e.g. `[#2345 :foo]`. The asset actor will see the scoped value as `*scope*` when called.
6767

6868
A Vector-based asset path SHOULD be used to allow a single actor to implement many different digital assets, e.g.
6969

70-
- Currencies might be designated by an asset path of `[#123456 :USD]`
71-
- Derivative contracts such as put options might have an asset path that includes the underlying asset, strike price and expiry time e.g. `[#98765 [#12345 :USD] 12500 1741948885345]`
72-
- Bets on a football match might specify the match date and selected winner `[#8978 "2023-6-06" "Manchester United"]` (note that a bet on a different outcome of the same match would be a different fungible asset since they are not mutually fungible)
70+
- Currencies might be designated by an asset path like `[#123456 :USD]`
71+
- Derivative contracts such as put options might have an asset path that includes the underlying asset, strike price and expiry time e.g. `[#98765 [[#12345 :USD] 12500 1741948885345]]`
72+
- Bets on a football match might specify the match date and selected winner `[#8978 ["2023-6-06" "Manchester United"]]` (note that a bet on a different outcome of the same match would be a different fungible asset since they are not mutually fungible)
7373

7474
### Quantities
7575

@@ -79,18 +79,22 @@ Because we want to enable innovation in the types and representations of assets,
7979

8080
Quantities for any asset MUST be a **commutative monoid** (in the mathematical sense). This requirement is necessary in order for addition, subtraction and comparison of asset quantities to behave in well-defined ways.
8181

82-
Assets MUST define an **addition** function enable quantities to be additively combined, i.e. given any two quantities of an asset it should be possible to use the addition function to compute the total quantity. This is equivalent to the addition function of the commutative monoid.
82+
Assets MUST define an **addition** function enable quantities to be additively combined, i.e. given any two valid quantities of an asset it MUST be possible to use the addition function to compute the total quantity. This is equivalent to the addition function of the commutative monoid.
8383

84-
Assets MUST define a **comparison** function enabling quantities to compared, i.e. given any two quantities of an asset it should be possible to use the comparison function to determine if one quantity is a subset of the other. This is equivalent to the algebraic pre-ordering of the monoid.
84+
Assets MUST define a **comparison** function enabling quantities to compared, i.e. given any two quantities of an asset it MUST be possible to use the comparison function to determine if one quantity is a subset of the other. This is equivalent to the algebraic pre-ordering of the monoid.
8585

86-
Assets MUST define a **subtraction** function enabling quantities to be subtracted, i.e. given two quantities of an asset where the first is "larger" than the second (as defined by the comparison function), it should be possible to subtract the second value from the first and get a result that is also a valid quantity.
86+
Assets MUST define a **subtraction** function enabling quantities to be subtracted, i.e. given two quantities of an asset where the first is "larger" than the second (as defined by the comparison function), it MUST be possible to subtract the second value from the first and get a result that is also a valid quantity.
8787

88-
Assets MUST define a **zero** quantity that logically represents an empty holding of an asset. This zero value is the identity element of the commutative monoid. The zero quantity itself will usually an "empty" value such as `#{}` or `0`.
88+
Assets MUST define a **zero** quantity that logically represents an empty holding of an asset. This zero value is the identity element of the commutative monoid. The zero quantity will usually be an "empty" value such as `#{}` or `0`.
8989

9090
The zero quantity SHOULD be the default balance of all accounts. Logically, an account should have a zero holding of an asset until some quantity of the asset is otherwise obtained. An example of an exception to this might be an asset implementation that gives a free non-zero quantity of the asset to all accounts, though this is probably unwise given the obvious potential for abuse.
9191

9292
For any given Asset, it MUST be possible to identify a Holding of the Asset for a given Account, where the Holding is the Quantity of the Asset that the Account owns.
9393

94+
An asset implementation MAY permit quantities to be specified using non-canonical values, provided that it MUST behave as if the equivalent canonical quantity was provided. For example, a NFT actor could reasonably consider a non-set value such as `123` to refer to the singleton set `#{123}` representing a single numbered NFT.
95+
96+
An asset implementation MAY attempt to produce reasonable results where quantity operations are passed arguments that are not normally valid, e.g. subtracting `3000` from `1000` would reasonably produce the result `-2000`, even though this is not a valid balance. However users of assets SHOULD NOT rely on this behaviour (in this case, subtraction is invalid because the first argument is "less than" the amount subtracted).
97+
9498
When passed as an argument to an asset implementation, the value `nil` MUST be treated as the zero quantity. This requirement ensures that a zero-equivalent value is known for all implementations, and can be used by generic code without having incurring the cost of explicitly querying the zero value.
9599

96100
#### Quantity examples
@@ -132,15 +136,23 @@ Offers SHOULD remain open at the discretion of the offering account. However, cl
132136

133137
## User API
134138

135-
The user API for the Asset Model is provided by the library `convex.asset`.
139+
The user API for the Asset Model is provided by the library `convex.asset`. Examples below assume the user has imported an alias for `convex.asset` library e.g.
140+
141+
```clojure
142+
(import convex.asset :as asset)
143+
```
136144

137145
Users do not need to use the `convex.asset` library to work with Convex digital assets - they are free to access the underlying actor functions directly. However the user API presents a convenient, well-tested interface that should be suitable for most purposes.
138146

147+
:::warning
148+
`convex.asset` is a library, which means that functions run in the context of the account that invokes them. Only do this with a trusted library, i.e. be sure you have imported the correct library. The address of the standard `convex.asset` is `#65` on Protonet.
149+
:::
150+
139151
### `balance`
140152

141153
The `balance` function gets the total quantity of an asset currently held by an account.
142154

143-
```
155+
```clojure
144156
(asset/balance some-fungible-asset *address*)
145157
=> 1500
146158

@@ -153,25 +165,103 @@ The returned value should always be a valid quantity for the specified asset. In
153165

154166
If the address argument is omitted, the balance for the current account is queried (i.e. an implicit `*address*` argument is used to specify the current account).
155167

168+
### `transfer`
169+
170+
The `transfer` function transfers a quantity of an asset to a recipient.
171+
172+
```clojure
173+
;; This transfers to account #13 1000 units of MY_TOKEN
174+
(asset/transfer #13 [MY-TOKEN 1000])
175+
```
176+
177+
As an alternative form, `transfer` may be called with an asset path and quantity as separate arguments:
178+
179+
```clojure
180+
;; This transfers to account #13 1000 units of MY_TOKEN
181+
(asset/transfer #13 MY-TOKEN 1000)
182+
```
183+
184+
The receiving account MAY implement a `^:callable receive-asset` function, in which case instead of directly transferring the asset, the asset will be *offered* and `receive-asset` will be called. Actors could, for example, use this so that they can automatically reject assets that they are not supposed to receive, and `accept` assets that they can handle.
185+
186+
`transfer` MUST fail if the caller does not have the quantity of assets specified. This SHOULD be a `:FUNDS` error, since this is conventionally used to indicate the lack of a sufficient asset quantity.
187+
188+
### `offer`
189+
190+
Making an `offer` makes a quantity of an asset available for a subsequent `accept` by a nominated receiver.
191+
192+
```clojure
193+
(asset/offer receiver [fungible-token-address 1000])
194+
```
195+
196+
:::warning
197+
If executed, an offer stays open until explicitly closed (by setting the quantity to zero). Users are advised to be cautious about making offers unless they expect the offer to be immediately accepted on terms they approve of (or rolled back in case of error) since the receiver may accept the offer at some arbitrary point in the future.
198+
:::
199+
200+
Asset implementations SHOULD reclaim memory by removing any offer records if the offer is set to the zero quantity. Failure to do so may result in wasted memory allowances.
201+
202+
### `get-offer`
203+
204+
The current offer of an asset from any sender to any receiver can be obtained with the `get-offer` function:
205+
206+
```clojure
207+
(asset/get-offer fungible-token-address sender receiver)
208+
```
209+
210+
Asset implementations MUST return the current offer, i.e. the quantity last specified via `offer` from the sender to the receiver minus any quantities subsequently accepted with `accept`.
211+
212+
Asset implementations MUST return the zero value if an offer does not exist.
213+
214+
### `accept`
215+
216+
An offer may be accepted by a receiver as follows:
217+
218+
```clojure
219+
(asset/accept sender [fungible-token-address 1000])
220+
```
221+
222+
Often, the sender will be the `*caller*` to an actor function which needs to take a quantity of an asset from the caller, e.g. as part of an atomic value exchange or as a payment of fees.
223+
224+
Asset acceptance MUST fail with a `:FUNDS` error if the quantity could not be accepted because it exceeds the sender's current balance.
225+
226+
If accepted, the asset implementation MUST:
227+
- Transfer the specified quantity of the asset from the sender to the receiver
228+
- Subtract the accepted quantity from the offer (which may result in it becoming zero)
229+
230+
### `owns?`
231+
232+
Tests whether a given address owns the specified quantity of an asset:
233+
234+
```clojure
235+
(asset/owns? #1456 fungible-token-address 1000)
236+
237+
;; alternative argument layout with an asset vector
238+
(asset/owns? #1456 [fungible-token-address 1000])
239+
```
240+
241+
The `owns?` function MUST return true if and only if the balance of the owner is at least as large as the specified quantity, i.e. the owner would normally be able to `transfer` this amount.
242+
156243
### `total-supply`
157244

158-
The `total-supply` function obtains the current total supply of an asset.
245+
The `total-supply` function obtains the current total supply of an asset, if available.
159246

160247
```clojure
161248
(asset/total-supply my-token)
162249
=> 1000000000000000000
163250
```
164251

165-
The `total-supply` function MAY return `nil` if the asset does not support efficient computation of the total supply.
252+
The result (if available) MUST equal the sum of all current balances of the asset.
253+
254+
The `total-supply` function MAY return `nil` if the asset does not support computation of the total supply.
166255

167-
The total supply of an asset may change during the lifetime of an asset, e.g. because new quantities are minted or burned.
256+
The total supply of an asset MAY change during the lifetime of an asset, e.g. because new quantities are minted or burned.
168257

258+
Asset implementations SHOULD cache the total supply by keeping track of the total quantity of an asset created or destroyed, e.g. via mint and burn operations. This allows the total supply to be provided without adding up all current balances, which is likely to be unreasonably expensive for callers.
169259

170260
## Security considerations
171261

172262
### Untrusted assets
173263

174-
Assets are implemented by Actors in the Convex asset model, and as such there are a number of issues that may arise if untrusted assets are used.
264+
Assets are implemented by actors in the Convex asset model, and as such there are a number of issues that may arise if untrusted assets are used.
175265

176266
The general recommendation is that users SHOULD NOT interact with untrusted assets.
177267

0 commit comments

Comments
 (0)