Skip to content

Commit 31a6d11

Browse files
committed
fix name and format
1 parent cee96a3 commit 31a6d11

File tree

1 file changed

+90
-89
lines changed

1 file changed

+90
-89
lines changed
Lines changed: 90 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313

1414
# Problem Statement
1515

16-
XLS-20 is a Non-Fungible Token standard that is currently active and in-use on the XRP Ledger main-net. Despite this, many developers and users of the XRPL remain unsatisfied by its complexity, unusual edge-cases, lack of first-class object NFTs, and general difficulty to understand and write integrations for. We therefore propose a light-weight alternative: *URIToken*.
16+
XLS-20 is a Non-Fungible Token standard that is currently active and in-use on the XRP Ledger main-net. Despite this, many developers and users of the XRPL remain unsatisfied by its complexity, unusual edge-cases, lack of first-class object NFTs, and general difficulty to understand and write integrations for. We therefore propose a light-weight alternative: _URIToken_.
1717

1818
# Amendment
1919

@@ -24,70 +24,69 @@ The amendment adds:
2424
A new type of ledger object: `ltURI_TOKEN`
2525
A new serialized field: `URITokenID`
2626
Five new transaction types:
27-
* `URITokenMint`
28-
* `URITokenBurn`
29-
* `URITokenBuy`
30-
* `URITokenCreateSellOffer`
31-
* `URITokenCancelSellOffer`
27+
28+
- `URITokenMint`
29+
- `URITokenBurn`
30+
- `URITokenBuy`
31+
- `URITokenCreateSellOffer`
32+
- `URITokenCancelSellOffer`
3233

3334
## New Ledger Object Type: `URIToken`
3435

35-
The `ltURI_TOKEN` object is an owned first-class on-ledger object which lives in its owner's directory. It is uniquely identified by the combined hash of its `Issuer` (minter) and the `URI`. Therefore an issuer can only issue one `URIToken` per URI. Upon creation (minting) the Issuer is the object's first Owner. You cannot mint on behalf of a third party. As with other first class objects, each URIToken locks up an owner reserve on the account that currently owns it. Disposing of a URIToken frees up these reserved funds.
36+
The `ltURI_TOKEN` object is an owned first-class on-ledger object which lives in its owner's directory. It is uniquely identified by the combined hash of its `Issuer` (minter) and the `URI`. Therefore an issuer can only issue one `URIToken` per URI. Upon creation (minting) the Issuer is the object's first Owner. You cannot mint on behalf of a third party. As with other first class objects, each URIToken locks up an owner reserve on the account that currently owns it. Disposing of a URIToken frees up these reserved funds.
3637

3738
The object has the following fields:
3839

39-
| Field | Type | Required | Description |
40-
| --- | --- | --- | --- |
41-
| sfIssuer | AccountID | ✔️ | The minter who issued the token. |
42-
| sfOwner | AccountID | ✔️ | The current owner of the token. |
43-
| sfURI | VL blob | ✔️ | The URI the token points to. |
44-
| sfFlags | UInt32 | ✔️ | A flag indicating whether or not the URIToken is burnable, and whether or not it is for sale. |
45-
| sfDigest | Hash256 || An sha512half integrity digest of the contents pointed to by the URI |
46-
| sfAmount | Amount || If the URIToken is for sale, then this is the amount the seller is asking for. |
47-
| sfDestination | AccountID || If the URIToken is for sale and this field has been set then only this AccountID may purchase the token. |
40+
| Field | Type | Required | Description |
41+
| ------------- | --------- | -------- | -------------------------------------------------------------------------------------------------------- |
42+
| sfIssuer | AccountID | ✔️ | The minter who issued the token. |
43+
| sfOwner | AccountID | ✔️ | The current owner of the token. |
44+
| sfURI | VL blob | ✔️ | The URI the token points to. |
45+
| sfFlags | UInt32 | ✔️ | A flag indicating whether or not the URIToken is burnable, and whether or not it is for sale. |
46+
| sfDigest | Hash256 | | An sha512half integrity digest of the contents pointed to by the URI |
47+
| sfAmount | Amount | | If the URIToken is for sale, then this is the amount the seller is asking for. |
48+
| sfDestination | AccountID | | If the URIToken is for sale and this field has been set then only this AccountID may purchase the token. |
4849

4950
Example URIToken object:
5051

5152
```json
5253
{
53-
"Flags":0,
54-
"Issuer":"rN38hTretqygfgcvADnJwZzHu5rawAvmkX",
55-
"LedgerEntryType":"URIToken",
56-
"Owner":"rN38hTretqygfgcvADnJwZzHu5rawAvmkX",
57-
"URI":"68747470733A2F2F6D656469612E74656E6F722E636F6D2F666752755A7A662D374B5541414141642F6465616C2D776974682D69742D73756E676C61737365732E676966"
54+
"Flags": 0,
55+
"Issuer": "rN38hTretqygfgcvADnJwZzHu5rawAvmkX",
56+
"LedgerEntryType": "URIToken",
57+
"Owner": "rN38hTretqygfgcvADnJwZzHu5rawAvmkX",
58+
"URI": "68747470733A2F2F6D656469612E74656E6F722E636F6D2F666752755A7A662D374B5541414141642F6465616C2D776974682D69742D73756E676C61737365732E676966"
5859
}
59-
6060
```
6161

6262
## New Transaction Type: `URITokenMint`
6363

64-
| Field | Type | Required | Description |
65-
| --- | --- | --- | --- |
66-
| sfURI | VL blob | ✔️ | The URI the token points to. |
67-
| sfDigest | Hash256 || An SHA512-Half integrity digest of the contents pointed to by the URI |
68-
| sfFlags | UInt32 || tfBurnable (0x00000001) or 0 or absent |
64+
| Field | Type | Required | Description |
65+
| -------- | ------- | -------- | --------------------------------------------------------------------- |
66+
| sfURI | VL blob | ✔️ | The URI the token points to. |
67+
| sfDigest | Hash256 | | An SHA512-Half integrity digest of the contents pointed to by the URI |
68+
| sfFlags | UInt32 | | tfBurnable (0x00000001) or 0 or absent |
6969

7070
If `sfDigest` is specified then the minted token will contain the hash specified by this field. For the end user this means they can verify the content served at the URI against this immutable hash, to ensure, for example that the properties of the NFT are not maliciously altered by changing the content at the URI. It may also be desirable to have a dynamic NFT where the content is intended to be altered, in which case simply omit `sfDigest` during minting, and the resulting URIToken will not contain this field.
7171

72-
‼️ If `sfFlags` is present and set to tfBurnable then the URIToken may be later burned by the Issuer. If the Hooks amendment is active on the chain this flag also indicates that the Issuer is a *strong transactional stakeholder*. In this event the Issuer's hooks will be executed whenever an attempt to buy or sell this URIToken occurs, and those hooks may reject the transaction and prevent it from happening if their own internal logic is not satisfied. It is therefore highly advisable to check whether or not a URIToken has `tfBurnable` set before purchasing or accepting it in trade.
72+
‼️ If `sfFlags` is present and set to tfBurnable then the URIToken may be later burned by the Issuer. If the Hooks amendment is active on the chain this flag also indicates that the Issuer is a _strong transactional stakeholder_. In this event the Issuer's hooks will be executed whenever an attempt to buy or sell this URIToken occurs, and those hooks may reject the transaction and prevent it from happening if their own internal logic is not satisfied. It is therefore highly advisable to check whether or not a URIToken has `tfBurnable` set before purchasing or accepting it in trade.
7373

7474
Example Mint:
7575

7676
```json
7777
{
78-
"Account":"raKG2uCwu71ohFGo1BJr7xqeGfWfYWZeh3",
79-
"Digest":"894E3B7ECDC9F6D00EE1D892F86E9BF0098F86BBD6CBB94D6ABFD78030EB5B9B",
80-
"TransactionType":"URITokenMint",
81-
"URI":"68747470733A2F2F6D656469612E74656E6F722E636F6D2F666752755A7A662D374B5541414141642F6465616C2D776974682D69742D73756E676C61737365732E6A736F6E"
78+
"Account": "raKG2uCwu71ohFGo1BJr7xqeGfWfYWZeh3",
79+
"Digest": "894E3B7ECDC9F6D00EE1D892F86E9BF0098F86BBD6CBB94D6ABFD78030EB5B9B",
80+
"TransactionType": "URITokenMint",
81+
"URI": "68747470733A2F2F6D656469612E74656E6F722E636F6D2F666752755A7A662D374B5541414141642F6465616C2D776974682D69742D73756E676C61737365732E6A736F6E"
8282
}
83-
8483
```
8584

8685
## New Transaction Type: `URITokenBurn`
8786

88-
| Field | Type | Required | Description |
89-
| --- | --- | --- | --- |
90-
| sfURITokenID | Hash256 | ✔️ | The Keylet for the URIToken object being destroyed |
87+
| Field | Type | Required | Description |
88+
| ------------ | ------- | -------- | -------------------------------------------------- |
89+
| sfURITokenID | Hash256 | ✔️ | The Keylet for the URIToken object being destroyed |
9190

9291
The current owner of the URIToken can burn it at any time.
9392

@@ -99,35 +98,35 @@ Example Burn:
9998

10099
```json
101100
{
102-
"Account":"r9XAC6zP5Db4qZBgRbweKUPtroxYnydTEQ",
103-
"TransactionType":"URITokenBurn",
104-
"URITokenID":"0FAC3CD45FCB800BB9CCCF907775E7D4FB167847D8999FF05CE7456D6C3A70FA",
101+
"Account": "r9XAC6zP5Db4qZBgRbweKUPtroxYnydTEQ",
102+
"TransactionType": "URITokenBurn",
103+
"URITokenID": "0FAC3CD45FCB800BB9CCCF907775E7D4FB167847D8999FF05CE7456D6C3A70FA"
105104
}
106105
```
107106

108107
## New Transaction Type: `URITokenCreateSellOffer`
109108

110-
A user may offer to sell their URIToken for a preset amount. A given URIToken may have at most one current sell offer. There are no buy offers. If a user executes a URITokenBuy then it must immediately cross an existing sell offer.
109+
A user may offer to sell their URIToken for a preset amount. A given URIToken may have at most one current sell offer. There are no buy offers. If a user executes a URITokenBuy then it must immediately cross an existing sell offer.
111110

112111
To offer the URIToken for sale: specify its `URITokenID`, an `Amount` to sell for, and optionally a `Destination`. If Destination is set then only the specified account may purchase the URIToken. If the Amount is 0 then a Destination must be set. (This prevents an accidental "transfer to anyone" scenario.)
113112

114113
If a previous sell offer was present on the URIToken then it is simply replaced with the new offer.
115114

116-
| Field | Type | Required | Description |
117-
| --- | --- | --- | --- |
118-
| sfURITokenID | Hash256 | ✔️ | The Keylet for the URIToken object being offered for sale |
119-
| sfAmount | Amount | ✔️ | The minimum amount a buyer must pay to purchase this URIToken. May be an IOU or XRP. |
120-
| sfDestination | AccountID || If provided then only this account may purchase the URIToken. |
115+
| Field | Type | Required | Description |
116+
| ------------- | --------- | -------- | ------------------------------------------------------------------------------------ |
117+
| sfURITokenID | Hash256 | ✔️ | The Keylet for the URIToken object being offered for sale |
118+
| sfAmount | Amount | ✔️ | The minimum amount a buyer must pay to purchase this URIToken. May be an IOU or XRP. |
119+
| sfDestination | AccountID | | If provided then only this account may purchase the URIToken. |
121120

122121
Example Sell:
123122

124123
```json
125124
{
126-
"Account":"r9XAC6zP5Db4qZBgRbweKUPtroxYnydTEQ",
127-
"Amount":"100000",
128-
"Flags":524288,
129-
"TransactionType":"URITokenCreateSellOffer",
130-
"URITokenID":"0FAC3CD45FCB800BB9CCCF907775E7D4FB167847D8999FF05CE7456D6C3A70FA",
125+
"Account": "r9XAC6zP5Db4qZBgRbweKUPtroxYnydTEQ",
126+
"Amount": "100000",
127+
"Flags": 524288,
128+
"TransactionType": "URITokenCreateSellOffer",
129+
"URITokenID": "0FAC3CD45FCB800BB9CCCF907775E7D4FB167847D8999FF05CE7456D6C3A70FA"
131130
}
132131
```
133132

@@ -139,52 +138,53 @@ Whether a URIToken is for sale is indicated by the presence of the `Amount` fiel
139138

140139
To purchase the URIToken, a user specifies its `URITokenID` and a purchase `Amount`. The purchase amount must be at least the amount specified in the sell offer (but may also exceed if the user wishes to tip the seller.) The purchase amount must be the same currency as the amount in the sell offer. No pathing is allowed in this transaction. The user must have sufficient currency available to cover the purchase.
141140

142-
| Field | Type | Required | Description |
143-
| --- | --- | --- | --- |
144-
| sfURITokenID | Hash256 | ✔️ | The Keylet for the URIToken object being purchased. |
145-
| sfAmount | Amount | ✔️ | The purchase price the buyer is willing to send. Must be the same currency as the sell offer. May not be less than the sale amount. |
141+
| Field | Type | Required | Description |
142+
| ------------ | ------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------- |
143+
| sfURITokenID | Hash256 | ✔️ | The Keylet for the URIToken object being purchased. |
144+
| sfAmount | Amount | ✔️ | The purchase price the buyer is willing to send. Must be the same currency as the sell offer. May not be less than the sale amount. |
146145

147146
Example Buy:
148147

149148
```json
150149
{
151-
"Account":"rpiLN1C94hGKGpLUbhsadVHzdSXtB2Ldra",
152-
"Amount":"100001",
153-
"TransactionType":"URITokenBuy",
154-
"URITokenID":"0FAC3CD45FCB800BB9CCCF907775E7D4FB167847D8999FF05CE7456D6C3A70FA"
150+
"Account": "rpiLN1C94hGKGpLUbhsadVHzdSXtB2Ldra",
151+
"Amount": "100001",
152+
"TransactionType": "URITokenBuy",
153+
"URITokenID": "0FAC3CD45FCB800BB9CCCF907775E7D4FB167847D8999FF05CE7456D6C3A70FA"
155154
}
156155
```
157156

158157
## New Transaction Type: `URITokenCancelSellOffer`
159158

160159
When a user has offered their URIToken for sale and later changes their mind, they may perform a clear operation. A clear operation simply clears the current sell offer from the URIToken.
161160

162-
| Field | Type | Required | Description |
163-
| --- | --- | --- | --- |
164-
| sfURITokenID | Hash256 | ✔️ | The Keylet for the URIToken object being cleared of any active sell offer. |
161+
| Field | Type | Required | Description |
162+
| ------------ | ------- | -------- | -------------------------------------------------------------------------- |
163+
| sfURITokenID | Hash256 | ✔️ | The Keylet for the URIToken object being cleared of any active sell offer. |
165164

166165
Example Clear
167166

168167
```json
169168
{
170-
"Account":"rpiLN1C94hGKGpLUbhsadVHzdSXtB2Ldra",
171-
"TransactionType":"URITokenCancelSellOffer",
172-
"URITokenID":"0FAC3CD45FCB800BB9CCCF907775E7D4FB167847D8999FF05CE7456D6C3A70FA"
169+
"Account": "rpiLN1C94hGKGpLUbhsadVHzdSXtB2Ldra",
170+
"TransactionType": "URITokenCancelSellOffer",
171+
"URITokenID": "0FAC3CD45FCB800BB9CCCF907775E7D4FB167847D8999FF05CE7456D6C3A70FA"
173172
}
174173
```
175174

176175
# Schema / Metadata Content
177176

178177
The URI pointed to by a URIToken should resolve to a JSON document that follows the below schema.
179178

180-
This schema may be extended over time as additional categories and use-cases present themselves.
179+
This schema may be extended over time as additional categories and use-cases present themselves.
181180

182-
‼️ Note that the `Digest`, if provided during Minting, is the hash of this JSON document **not** the content pointed to by the JSON document. The `Digest` is calculated by taking the SHA-512 Half of the stringified, whitespace trimmed content JSON.
181+
‼️ Note that the `Digest`, if provided during Minting, is the hash of this JSON document **not** the content pointed to by the JSON document. The `Digest` is calculated by taking the SHA-512 Half of the stringified, whitespace trimmed content JSON.
183182

184183
- Schema gist: https://gist.github.com/WietseWind/83cd89906ed79fb510ec1eae3fc70bb6
185184
- Sample digest generator gist: https://gist.github.com/WietseWind/d5072777814b6f239c3baba5cbe29e39
186185

187186
## JSON Schema
187+
188188
```js
189189
export interface xls35category {
190190
code: string
@@ -221,7 +221,7 @@ export interface xls35schema {
221221
url: string
222222
digest?: string
223223
}
224-
224+
225225
// Custom external information, to match your own specified schema (^^)
226226
content?: {
227227
url: string
@@ -247,41 +247,42 @@ export interface xls35schema {
247247
title: string
248248
}
249249
attachments?: xls35attachment[]
250-
}
250+
}
251251
}
252252
```
253253

254254
## Example JSON document
255+
255256
```json
256257
{
257-
"content":{
258-
"url":"https://someuri"
259-
},
260-
"details":{
261-
"title":"Some URIToken",
262-
"categories":[
263-
"0000"
264-
],
265-
"publisher":{
266-
"name":"XRPL-Labs"
267-
}
268-
}
258+
"content": {
259+
"url": "https://someuri"
260+
},
261+
"details": {
262+
"title": "Some URIToken",
263+
"categories": ["0000"],
264+
"publisher": {
265+
"name": "XRPL-Labs"
266+
}
267+
}
269268
}
270269
```
271270

272271
## Computing the `Digest` over your JSON document
272+
273273
Pseudo-code:
274+
274275
```js
275276
metadata = {
276-
"details": {
277-
"title": "Some Title"
278-
}
279-
}
277+
details: {
278+
title: "Some Title",
279+
},
280+
};
280281

281-
jsonstring = json_encode(metadata)
282-
whitespaceremoved = trim(jsonstring)
283-
hash = sha512(whitespaceremoved)
284-
sha512half = slice(hash, 0, 64)
282+
jsonstring = json_encode(metadata);
283+
whitespaceremoved = trim(jsonstring);
284+
hash = sha512(whitespaceremoved);
285+
sha512half = slice(hash, 0, 64);
285286

286-
digest = sha512half
287+
digest = sha512half;
287288
```

0 commit comments

Comments
 (0)