Compare commits

..

6 Commits

Author SHA1 Message Date
Rome Reginelli
9d4633b174 Apply suggestions from @oeggert review
Co-authored-by: oeggert <117319296+oeggert@users.noreply.github.com>
2025-09-17 16:31:26 -07:00
mDuo13
23661cea5a Update tutorial guidelines per review 2025-08-13 14:11:21 -07:00
mDuo13
39cb3de81d Revise tutorial template per feedback 2025-08-13 13:46:47 -07:00
mDuo13
e5d261ea04 Add env var as an option for secret keys 2025-08-12 11:25:28 -07:00
mDuo13
58b2b5be69 Revise tutorial guidelines 2025-08-11 18:47:35 -07:00
mDuo13
0d81c67039 Draft revised tutorial structure/template 2025-08-11 16:20:22 -07:00
85 changed files with 1773 additions and 1699 deletions

View File

@@ -14,8 +14,8 @@
[AMMVoteトランザクション]: /@l10n/ja/docs/references/protocol/transactions/types/ammvote.md
[AMMWithdraw]: /@l10n/ja/docs/references/protocol/transactions/types/ammwithdraw.md
[AMMWithdrawトランザクション]: /@l10n/ja/docs/references/protocol/transactions/types/ammwithdraw.md
[API v1]: /@l10n/ja/docs/references/http-websocket-apis/index.md
[API v2]: /@l10n/ja/docs/references/http-websocket-apis/index.md
[API v1]: /@l10n/ja/docs/references/http-websocket-apis/api-conventions/request-formatting.md#api-versioning
[API v2]: /@l10n/ja/docs/references/http-websocket-apis/api-conventions/request-formatting.md#api-versioning
[AccountDelete]: /@l10n/ja/docs/references/protocol/transactions/types/accountdelete.md
[AccountDeleteトランザクション]: /@l10n/ja/docs/references/protocol/transactions/types/accountdelete.md
[AccountRootエントリ]: /@l10n/ja/docs/references/protocol/ledger-data/ledger-entry-types/accountroot.md

View File

@@ -81,7 +81,7 @@ rippled -- account_tx rLNaPoKeeBjZe2qs6x52yVPZpZ8td4dc6w -1 -1 2 0 binary descen
| `marker` | [マーカー][] | 以前にページネーションされたレスポンスの値。そのレスポンスを停止した箇所からデータの取得を再開します。サーバが使用できるレジャーの範囲に変更があっても、この値は変わりません。 |
- リクエスト内で次の各フィールドのうち1つ以上を使用する必要があります: `ledger_index``ledger_hash``ledger_index_min`、または`ledger_index_max`
- [API v2][] `ledger_index``ledger_hash`のどちらかを指定した場合、`ledger_index_min``ledger_index_max`を含めると`invalidParams`エラーが返ります。
- [API v2] `ledger_index``ledger_hash`のどちらかを指定した場合、`ledger_index_min``ledger_index_max`を含めると`invalidParams`エラーが返ります。
### 照会されたデータの繰り返し

View File

@@ -139,10 +139,6 @@ footer.community.report-a-scam: 詐欺の報告
component.tryit: 試してみる
component.queryexampletx: トランザクションの例を確認
component.amendment-status.requires.1: " "
component.amendment-status.requires.2: が必要です。
component.amendment-status.added.1: " "
component.amendment-status.added.2: により追加されました。
# Amendment tracker translations
amendment.loading: ロード中Amendments...

View File

@@ -380,103 +380,3 @@ function AmendmentBadge(props: { amendment: Amendment }) {
return <img src={badgeUrl} alt={status} className="shield" />;
}
export function AmendmentDisclaimer(props: {
name: string,
compact: boolean
}) {
const [amendmentStatus, setStatus] = React.useState<Amendment | null>(null);
const [loading, setLoading] = React.useState(true);
const [error, setError] = React.useState<string | null>(null);
const { useTranslate } = useThemeHooks();
const { translate } = useTranslate();
const link = () => <Link to={`/resources/known-amendments#${props.name.toLowerCase()}`}>{props.name}{ props.compact ? "" : " amendment"}</Link>
React.useEffect(() => {
const fetchAmendments = async () => {
try {
setLoading(true);
const response = await fetch(`https://vhs.prod.ripplex.io/v1/network/amendments/vote/main/`);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data: AmendmentsResponse = await response.json()
console.log("data.amendments is:", data.amendments)
let found_amendment = false
for (const amendment of data.amendments) {
if (amendment.name == props.name) {
setStatus(amendment)
found_amendment = true
break
}
}
if (!found_amendment) {
throw new Error(`Couldn't find ${props.name} amendment in status table.`)
}
} catch (err) {
setError(err instanceof Error ? err.message : 'Failed to fetch amendments');
} finally {
setLoading(false)
}
}
fetchAmendments()
}, [])
if (loading) {
return (
<p><em>
{translate("component.amendment-status.requires.1", "Requires the ")}{link()}{translate("component.amendment-status.requires.2", ".")}
{" "}
<span className="spinner-border text-primary" role="status">
<span className="sr-only">{translate("amendment.loading_status", "Loading...")}</span>
</span>
</em></p>
)
}
if (error) {
return (
<p><em>
{translate("component.amendment-status.requires.1", "Requires the ")}{link()}{translate("component.amendment-status.requires.2", ".")}
{" "}
<span className="alert alert-danger" style={{display: "block"}}>
<strong>{translate("amendment.error_status", "Error loading amendment status")}:</strong> {error}
</span>
</em></p>
)
}
if (props.compact) {
return (
<>
{link()}
{" "}
<AmendmentBadge amendment={amendmentStatus} />
</>
)
}
return (
<p><em>(
{
amendmentStatus.date ? (
<>
{translate("component.amendment-status.added.1", "Added by the ")}{link()}
{translate("component.amendment-status.added.2", ".")}
{" "}
<AmendmentBadge amendment={amendmentStatus} />
</>
) : (
<>
{translate("component.amendment-status.requires.1", "Requires the ")}{link()}
{translate("component.amendment-status.requires.2", ".")}
{" "}
<AmendmentBadge amendment={amendmentStatus} />
</>
)
}
)</em></p>
)
}

View File

@@ -221,20 +221,3 @@ export const amendmentsTable: Schema & { tagName: string } = {
render: 'AmendmentsTable',
selfClosing: true
}
export const amendmentDisclaimer: Schema & { tagName: string } = {
tagName: 'amendment-disclaimer',
attributes: {
name: {
type: 'String',
required: true
},
compact: {
type: 'Boolean',
required: false,
default: false
}
},
render: 'AmendmentDisclaimer',
selfClosing: true
}

View File

@@ -1,253 +0,0 @@
{
"result": {
"account": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59",
"account_objects": [
{
"Balance": {
"currency": "ASP",
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
"value": "0"
},
"Flags": 65536,
"HighLimit": {
"currency": "ASP",
"issuer": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59",
"value": "0"
},
"HighNode": "0",
"LedgerEntryType": "RippleState",
"LowLimit": {
"currency": "ASP",
"issuer": "r3vi7mWxru9rJCxETCyA1CHvzL96eZWx5z",
"value": "10"
},
"LowNode": "0",
"PreviousTxnID": "BF7555B0F018E3C5E2A3FF9437A1A5092F32903BE246202F988181B9CED0D862",
"PreviousTxnLgrSeq": 1438879,
"index": "2243B0B630EA6F7330B654EFA53E27A7609D9484E535AB11B7F946DF3D247CE9"
},
{
"Balance": {
"currency": "JOE",
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
"value": "0"
},
"Flags": 2228224,
"HighLimit": {
"currency": "JOE",
"issuer": "rE6R3DWF9fBD7CyiQciePF9SqK58Ubp8o2",
"value": "100"
},
"HighNode": "0",
"LedgerEntryType": "RippleState",
"LowLimit": {
"currency": "JOE",
"issuer": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59",
"value": "0"
},
"LowNode": "0",
"PreviousTxnID": "8E488B0E939D4DACD62102A5BFA2FDC63679EFCC56F2FDA2FDF45283674BB711",
"PreviousTxnLgrSeq": 5989200,
"index": "273BD42DD72E7D84416ED759CEC92DACCD12A4502287E50BECF816233C021ED1"
},
{
"Balance": {
"currency": "USD",
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
"value": "0"
},
"Flags": 131072,
"HighLimit": {
"currency": "USD",
"issuer": "rEhDDUUNxpXgEHVJtC2cjXAgyx5VCFxdMF",
"value": "1"
},
"HighNode": "0",
"LedgerEntryType": "RippleState",
"LowLimit": {
"currency": "USD",
"issuer": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59",
"value": "0"
},
"LowNode": "0",
"PreviousTxnID": "B6B410172C0B65575D89E464AF5B99937CC568822929ABF87DA75CBD11911932",
"PreviousTxnLgrSeq": 6592159,
"index": "2CC2B211F6D1159B5CFD07AF8717A9C51C985E2497B2875C192EE87266AB0F81"
},
{
"Balance": {
"currency": "USD",
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
"value": "5"
},
"Flags": 1114112,
"HighLimit": {
"currency": "USD",
"issuer": "rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q",
"value": "0"
},
"HighNode": "0",
"LedgerEntryType": "RippleState",
"LowLimit": {
"currency": "USD",
"issuer": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59",
"value": "5"
},
"LowNode": "0",
"PreviousTxnID": "2A5C5D95880A254A2C57BB5332558205BC33B9F2B38D359A170283CB4CBD080A",
"PreviousTxnLgrSeq": 39498567,
"index": "2DECFAC23B77D5AEA6116C15F5C6D4669EBAEE9E7EE050A40FE2B1E47B6A9419"
},
{
"Balance": {
"currency": "EUR",
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
"value": "0.793598266778297"
},
"Flags": 1114112,
"HighLimit": {
"currency": "EUR",
"issuer": "rLEsXccBGNR3UPuPu2hUXPjziKC3qKSBun",
"value": "0"
},
"HighNode": "0",
"LedgerEntryType": "RippleState",
"LowLimit": {
"currency": "EUR",
"issuer": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59",
"value": "1"
},
"LowNode": "0",
"PreviousTxnID": "E9345D44433EA368CFE1E00D84809C8E695C87FED18859248E13662D46A0EC46",
"PreviousTxnLgrSeq": 5447146,
"index": "4513749B30F4AF8DA11F077C448128D6486BF12854B760E4E5808714588AA915"
},
{
"Balance": {
"currency": "CNY",
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
"value": "0"
},
"Flags": 2228224,
"HighLimit": {
"currency": "CNY",
"issuer": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59",
"value": "3"
},
"HighNode": "0",
"LedgerEntryType": "RippleState",
"LowLimit": {
"currency": "CNY",
"issuer": "rnuF96W4SZoCJmbHYBFoJZpR8eCaxNvekK",
"value": "0"
},
"LowNode": "8",
"PreviousTxnID": "2FDDC81F4394695B01A47913BEC4281AC9A283CC8F903C14ADEA970F60E57FCF",
"PreviousTxnLgrSeq": 5949673,
"index": "578C327DA8944BDE2E10C9BA36AFA2F43E06C8D1E8819FB225D266CBBCFDE5CE"
},
{
"Balance": {
"currency": "DYM",
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
"value": "1.336889190631542"
},
"Flags": 65536,
"HighLimit": {
"currency": "DYM",
"issuer": "rGwUWgN5BEg3QGNY3RX2HfYowjUTZdid3E",
"value": "0"
},
"HighNode": "0",
"LedgerEntryType": "RippleState",
"LowLimit": {
"currency": "DYM",
"issuer": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59",
"value": "3"
},
"LowNode": "0",
"PreviousTxnID": "6DA2BD02DFB83FA4DAFC2651860B60071156171E9C021D9E0372A61A477FFBB1",
"PreviousTxnLgrSeq": 8818732,
"index": "5A2A5FF12E71AEE57564E624117BBA68DEF78CD564EF6259F92A011693E027C7"
},
{
"Balance": {
"currency": "BTC",
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
"value": "0"
},
"Flags": 131072,
"HighLimit": {
"currency": "BTC",
"issuer": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59",
"value": "3"
},
"HighNode": "0",
"LedgerEntryType": "RippleState",
"LowLimit": {
"currency": "BTC",
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
"value": "0"
},
"LowNode": "43",
"PreviousTxnID": "03EDF724397D2DEE70E49D512AECD619E9EA536BE6CFD48ED167AE2596055C9A",
"PreviousTxnLgrSeq": 8317037,
"index": "767C12AF647CDF5FEB9019B37018748A79C50EDAF87E8D4C7F39F78AA7CA9765"
},
{
"Balance": {
"currency": "USD",
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
"value": "-11.68225001668339"
},
"Flags": 131072,
"HighLimit": {
"currency": "USD",
"issuer": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59",
"value": "5000"
},
"HighNode": "0",
"LedgerEntryType": "RippleState",
"LowLimit": {
"currency": "USD",
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
"value": "0"
},
"LowNode": "4a",
"PreviousTxnID": "8C55AFC2A2AA42B5CE624AEECDB3ACFDD1E5379D4E5BF74A8460C5E97EF8706B",
"PreviousTxnLgrSeq": 43251698,
"index": "826CF5BFD28F3934B518D0BDF3231259CBD3FD0946E3C3CA0C97D2C75D2D1A09"
},
{
"Balance": {
"currency": "USD",
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
"value": "0"
},
"Flags": 2228224,
"HighLimit": {
"currency": "USD",
"issuer": "rE6R3DWF9fBD7CyiQciePF9SqK58Ubp8o2",
"value": "100"
},
"HighNode": "0",
"LedgerEntryType": "RippleState",
"LowLimit": {
"currency": "USD",
"issuer": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59",
"value": "0"
},
"LowNode": "0",
"PreviousTxnID": "B1A7405C4A698E6A371E5B02836E779A942936AB754865FE82141E5280F09D1B",
"PreviousTxnLgrSeq": 5718137,
"index": "8DF1456AAB7470A760F6A095C156B457FF1038D43E6B11FD8011C2DF714E4FA1"
}
],
"ledger_hash": "E471A081996BB5CBB666AC99085CB8E3CA4D59DFCEDC0060B8701DC45A0EE423",
"ledger_index": 98162290,
"limit": 10,
"marker": "F60ADF645E78B69857D2E4AEC8B7742FEABC8431BD8611D099B428C3E816DF93,94A9F05FEF9A153229E2E997E64919FD75AAE2028C8153E8EBDB4440BD3ECBB5",
"status": "success",
"validated": true
}
}

View File

@@ -1,256 +0,0 @@
{
"id": "example_account_objects",
"result": {
"account": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59",
"account_objects": [
{
"Balance": {
"currency": "ASP",
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
"value": "0"
},
"Flags": 65536,
"HighLimit": {
"currency": "ASP",
"issuer": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59",
"value": "0"
},
"HighNode": "0",
"LedgerEntryType": "RippleState",
"LowLimit": {
"currency": "ASP",
"issuer": "r3vi7mWxru9rJCxETCyA1CHvzL96eZWx5z",
"value": "10"
},
"LowNode": "0",
"PreviousTxnID": "BF7555B0F018E3C5E2A3FF9437A1A5092F32903BE246202F988181B9CED0D862",
"PreviousTxnLgrSeq": 1438879,
"index": "2243B0B630EA6F7330B654EFA53E27A7609D9484E535AB11B7F946DF3D247CE9"
},
{
"Balance": {
"currency": "JOE",
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
"value": "0"
},
"Flags": 2228224,
"HighLimit": {
"currency": "JOE",
"issuer": "rE6R3DWF9fBD7CyiQciePF9SqK58Ubp8o2",
"value": "100"
},
"HighNode": "0",
"LedgerEntryType": "RippleState",
"LowLimit": {
"currency": "JOE",
"issuer": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59",
"value": "0"
},
"LowNode": "0",
"PreviousTxnID": "8E488B0E939D4DACD62102A5BFA2FDC63679EFCC56F2FDA2FDF45283674BB711",
"PreviousTxnLgrSeq": 5989200,
"index": "273BD42DD72E7D84416ED759CEC92DACCD12A4502287E50BECF816233C021ED1"
},
{
"Balance": {
"currency": "USD",
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
"value": "0"
},
"Flags": 131072,
"HighLimit": {
"currency": "USD",
"issuer": "rEhDDUUNxpXgEHVJtC2cjXAgyx5VCFxdMF",
"value": "1"
},
"HighNode": "0",
"LedgerEntryType": "RippleState",
"LowLimit": {
"currency": "USD",
"issuer": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59",
"value": "0"
},
"LowNode": "0",
"PreviousTxnID": "B6B410172C0B65575D89E464AF5B99937CC568822929ABF87DA75CBD11911932",
"PreviousTxnLgrSeq": 6592159,
"index": "2CC2B211F6D1159B5CFD07AF8717A9C51C985E2497B2875C192EE87266AB0F81"
},
{
"Balance": {
"currency": "USD",
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
"value": "5"
},
"Flags": 1114112,
"HighLimit": {
"currency": "USD",
"issuer": "rMwjYedjc7qqtKYVLiAccJSmCwih4LnE2q",
"value": "0"
},
"HighNode": "0",
"LedgerEntryType": "RippleState",
"LowLimit": {
"currency": "USD",
"issuer": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59",
"value": "5"
},
"LowNode": "0",
"PreviousTxnID": "2A5C5D95880A254A2C57BB5332558205BC33B9F2B38D359A170283CB4CBD080A",
"PreviousTxnLgrSeq": 39498567,
"index": "2DECFAC23B77D5AEA6116C15F5C6D4669EBAEE9E7EE050A40FE2B1E47B6A9419"
},
{
"Balance": {
"currency": "EUR",
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
"value": "0.793598266778297"
},
"Flags": 1114112,
"HighLimit": {
"currency": "EUR",
"issuer": "rLEsXccBGNR3UPuPu2hUXPjziKC3qKSBun",
"value": "0"
},
"HighNode": "0",
"LedgerEntryType": "RippleState",
"LowLimit": {
"currency": "EUR",
"issuer": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59",
"value": "1"
},
"LowNode": "0",
"PreviousTxnID": "E9345D44433EA368CFE1E00D84809C8E695C87FED18859248E13662D46A0EC46",
"PreviousTxnLgrSeq": 5447146,
"index": "4513749B30F4AF8DA11F077C448128D6486BF12854B760E4E5808714588AA915"
},
{
"Balance": {
"currency": "CNY",
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
"value": "0"
},
"Flags": 2228224,
"HighLimit": {
"currency": "CNY",
"issuer": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59",
"value": "3"
},
"HighNode": "0",
"LedgerEntryType": "RippleState",
"LowLimit": {
"currency": "CNY",
"issuer": "rnuF96W4SZoCJmbHYBFoJZpR8eCaxNvekK",
"value": "0"
},
"LowNode": "8",
"PreviousTxnID": "2FDDC81F4394695B01A47913BEC4281AC9A283CC8F903C14ADEA970F60E57FCF",
"PreviousTxnLgrSeq": 5949673,
"index": "578C327DA8944BDE2E10C9BA36AFA2F43E06C8D1E8819FB225D266CBBCFDE5CE"
},
{
"Balance": {
"currency": "DYM",
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
"value": "1.336889190631542"
},
"Flags": 65536,
"HighLimit": {
"currency": "DYM",
"issuer": "rGwUWgN5BEg3QGNY3RX2HfYowjUTZdid3E",
"value": "0"
},
"HighNode": "0",
"LedgerEntryType": "RippleState",
"LowLimit": {
"currency": "DYM",
"issuer": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59",
"value": "3"
},
"LowNode": "0",
"PreviousTxnID": "6DA2BD02DFB83FA4DAFC2651860B60071156171E9C021D9E0372A61A477FFBB1",
"PreviousTxnLgrSeq": 8818732,
"index": "5A2A5FF12E71AEE57564E624117BBA68DEF78CD564EF6259F92A011693E027C7"
},
{
"Balance": {
"currency": "BTC",
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
"value": "0"
},
"Flags": 131072,
"HighLimit": {
"currency": "BTC",
"issuer": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59",
"value": "3"
},
"HighNode": "0",
"LedgerEntryType": "RippleState",
"LowLimit": {
"currency": "BTC",
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
"value": "0"
},
"LowNode": "43",
"PreviousTxnID": "03EDF724397D2DEE70E49D512AECD619E9EA536BE6CFD48ED167AE2596055C9A",
"PreviousTxnLgrSeq": 8317037,
"index": "767C12AF647CDF5FEB9019B37018748A79C50EDAF87E8D4C7F39F78AA7CA9765"
},
{
"Balance": {
"currency": "USD",
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
"value": "-11.68225001668339"
},
"Flags": 131072,
"HighLimit": {
"currency": "USD",
"issuer": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59",
"value": "5000"
},
"HighNode": "0",
"LedgerEntryType": "RippleState",
"LowLimit": {
"currency": "USD",
"issuer": "rvYAfWj5gh67oV6fW32ZzP3Aw4Eubs59B",
"value": "0"
},
"LowNode": "4a",
"PreviousTxnID": "8C55AFC2A2AA42B5CE624AEECDB3ACFDD1E5379D4E5BF74A8460C5E97EF8706B",
"PreviousTxnLgrSeq": 43251698,
"index": "826CF5BFD28F3934B518D0BDF3231259CBD3FD0946E3C3CA0C97D2C75D2D1A09"
},
{
"Balance": {
"currency": "USD",
"issuer": "rrrrrrrrrrrrrrrrrrrrBZbvji",
"value": "0"
},
"Flags": 2228224,
"HighLimit": {
"currency": "USD",
"issuer": "rE6R3DWF9fBD7CyiQciePF9SqK58Ubp8o2",
"value": "100"
},
"HighNode": "0",
"LedgerEntryType": "RippleState",
"LowLimit": {
"currency": "USD",
"issuer": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59",
"value": "0"
},
"LowNode": "0",
"PreviousTxnID": "B1A7405C4A698E6A371E5B02836E779A942936AB754865FE82141E5280F09D1B",
"PreviousTxnLgrSeq": 5718137,
"index": "8DF1456AAB7470A760F6A095C156B457FF1038D43E6B11FD8011C2DF714E4FA1"
}
],
"ledger_hash": "59D7E38286AD80C402EC1533BFE002285E792698EEFA06BD3D5AEAC618B56B0A",
"ledger_index": 98162008,
"limit": 10,
"marker": "F60ADF645E78B69857D2E4AEC8B7742FEABC8431BD8611D099B428C3E816DF93,94A9F05FEF9A153229E2E997E64919FD75AAE2028C8153E8EBDB4440BD3ECBB5|NONFH",
"validated": true,
"_nodepref": "nonfh"
},
"status": "success",
"type": "response"
}

View File

@@ -6,27 +6,34 @@ Quick install & usage:
```sh
npm install
node ./verify_credential.js
```
`verify_credential.js` can also be used as a commandline utility. Full usage statement:
The output should look something like this:
```sh
$ ./verify_credential.js -h
Usage: verify-credential [options] [issuer] [subject] [credential_type]
Verify an XRPL credential
Arguments:
issuer Credential issuer address as base58 (default:
"rEzikzbnH6FQJ2cCr4Bqmf6c3jyWLzkonS")
subject Credential subject (holder) address as base58 (default:
"rsYhHbanGpnYe3M6bsaMeJT5jnLTfDEzoA")
credential_type Credential type as string. (default: "my_credential")
Options:
-b, --binary Use binary (hexadecimal) for credential_type
-n, --network <network> {devnet,testnet,mainnet} Use the specified network for lookup (default: "devnet")
-q, --quiet Don't print log messages
-h, --help display help for command
```text
Looking up credential...
{
"command": "ledger_entry",
"credential": {
"subject": "rsYhHbanGpnYe3M6bsaMeJT5jnLTfDEzoA",
"issuer": "rEzikzbnH6FQJ2cCr4Bqmf6c3jyWLzkonS",
"credential_type": "6D795F63726564656E7469616C"
},
"ledger_index": "validated"
}
Found credential:
{
"CredentialType": "6D795F63726564656E7469616C",
"Flags": 65536,
"Issuer": "rEzikzbnH6FQJ2cCr4Bqmf6c3jyWLzkonS",
"IssuerNode": "0",
"LedgerEntryType": "Credential",
"PreviousTxnID": "7D1257779E2D298C07C7E0C73CD446534B143FBD1F13DB268A878E40FD153B9A",
"PreviousTxnLgrSeq": 803275,
"Subject": "rsYhHbanGpnYe3M6bsaMeJT5jnLTfDEzoA",
"SubjectNode": "0",
"index": "9603F0E204A8B1C61823625682EB0ECE98A4ECF22FF46CD4845FA9BFA3606B24"
}
Credential is valid.
```

View File

@@ -1,18 +1,9 @@
{
"name": "issuer_service",
"version": "1.0.0",
"description": "",
"main": "verify_credential.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"name": "verify_credentials",
"version": "2.0.0",
"description": "Sample code showing how to check if a credential on the XRPL exists and is valid.",
"type": "module",
"dependencies": {
"commander": "^13.1.0",
"winston": "^3.17.0",
"xrpl": "^4.2.5"
}
}

View File

@@ -1,184 +1,68 @@
#!/usr/bin/env node
import { Client, rippleTimeToISOTime, convertStringToHex } from "xrpl"
import { Command } from "commander";
import { Client, rippleTimeToISOTime, convertStringToHex } from "xrpl";
import winston from "winston";
const client = new Client("wss://s.devnet.rippletest.net:51233")
await client.connect()
// Set up logging --------------------------------------------------------------
// Use WARNING by default in case verify_credential is called from elsewhere.
const logger = winston.createLogger({
level: "warn",
transports: [new winston.transports.Console()],
format: winston.format.simple(),
});
const subject_address = "rsYhHbanGpnYe3M6bsaMeJT5jnLTfDEzoA"
const issuer_address = "rEzikzbnH6FQJ2cCr4Bqmf6c3jyWLzkonS"
const credential_type = convertStringToHex("my_credential").toUpperCase()
// Define an error to throw when XRPL lookup fails unexpectedly
class XRPLLookupError extends Error {
constructor(error) {
super("XRPL look up error");
this.name = "XRPLLookupError";
this.body = error;
}
// Look up Credential ledger entry --------------------------------------------
const ledgerEntryRequest = {
command: "ledger_entry",
credential: {
subject: subject_address,
issuer: issuer_address,
credential_type: credential_type,
},
ledger_index: "validated",
}
console.log("Looking up credential...")
console.log(JSON.stringify(ledgerEntryRequest, null, 2))
const CREDENTIAL_REGEX = /^[0-9A-F]{2,128}$/;
// See https://xrpl.org/docs/references/protocol/ledger-data/ledger-entry-types/credential#credential-flags
// to learn more about the lsfAccepted flag.
const LSF_ACCEPTED = 0x00010000;
async function verifyCredential(client, issuer, subject, credentialType, binary=false) {
/**
* Check whether an XRPL account holds a specified credential,
* as of the most recently validated ledger.
* Parameters:
* client - Client for interacting with rippled servers.
* issuer - Address of the credential issuer, in base58.
* subject - Address of the credential holder/subject, in base58.
* credentialType - Credential type to check for as a string,
* which will be encoded as UTF-8 (1-128 characters long).
* binary - Specifies that the credential type is provided in hexadecimal format.
* You must provide the credential_type as input.
* Returns True if the account holds the specified, valid credential.
* Returns False if the credential is missing, expired, or not accepted.
*/
// Encode credentialType as uppercase hex, if needed
let credentialTypeHex = "";
if (binary) {
credentialTypeHex = credentialType.toUpperCase();
let xrplResponse
try {
xrplResponse = await client.request(ledgerEntryRequest)
} catch (err) {
if (err.data?.error === "entryNotFound") {
console.error("Credential was not found")
} else {
credentialTypeHex = convertStringToHex(credentialType).toUpperCase();
logger.info(`Encoded credential_type as hex: ${credentialTypeHex}`);
console.error(err)
}
process.exit(1)
}
if (credentialTypeHex.length % 2 !== 0 || !CREDENTIAL_REGEX.test(credentialTypeHex)) {
// Hexadecimal is always 2 chars per byte, so an odd length is invalid.
throw new Error("Credential type must be 128 characters as hexadecimal.");
}
const credential = xrplResponse.result.node
console.log("Found credential:")
console.log(JSON.stringify(credential, null, 2))
// Perform XRPL lookup of Credential ledger entry --------------------------
const ledgerEntryRequest = {
command: "ledger_entry",
credential: {
subject: subject,
issuer: issuer,
credential_type: credentialTypeHex,
},
// Check if the credential has been accepted ----------------------------------
const lsfAccepted = 0x00010000
if (!(credential.Flags & lsfAccepted)) {
console.log("Credential is not accepted.")
process.exit(2)
}
// Confirm that the credential is not expired ---------------------------------
if (credential.Expiration) {
const expirationTime = rippleTimeToISOTime(credential.Expiration)
console.log(`Credential has expiration: ${expirationTime}`)
console.log("Looking up validated ledger to check for expiration.")
const ledgerResponse = await client.request({
command: "ledger",
ledger_index: "validated",
};
logger.info("Looking up credential...");
logger.info(JSON.stringify(ledgerEntryRequest, null, 2));
})
let xrplResponse;
try {
xrplResponse = await client.request(ledgerEntryRequest);
} catch (err) {
if (err.data?.error === "entryNotFound") {
logger.info("Credential was not found");
return false;
} else {
// Other errors, for example invalidly specified addresses.
throw new XRPLLookupError(err?.data || err);
}
}
const closeTime = rippleTimeToISOTime(ledgerResponse.result.ledger.close_time)
console.log(`Most recent validated ledger was at: ${closeTime}`)
const credential = xrplResponse.result.node;
logger.info("Found credential:");
logger.info(JSON.stringify(credential, null, 2));
// Check if the credential has been accepted ---------------------------
if (!(credential.Flags & LSF_ACCEPTED)) {
logger.info("Credential is not accepted.");
return false
}
// Confirm that the credential is not expired ------------------------------
if (credential.Expiration) {
const expirationTime = rippleTimeToISOTime(credential.Expiration);
logger.info(`Credential has expiration: ${expirationTime}`);
logger.info("Looking up validated ledger to check for expiration.");
let ledgerResponse;
try {
ledgerResponse = await client.request({
command: "ledger",
ledger_index: "validated",
});
} catch (err) {
throw new XRPLLookupError(err?.data || err);
}
const closeTime = rippleTimeToISOTime(ledgerResponse.result.ledger.close_time);
logger.info(`Most recent validated ledger is: ${closeTime}`);
if (new Date(closeTime) > new Date(expirationTime)) {
logger.info("Credential is expired.");
return false;
}
}
// Credential has passed all checks ---------------------------------------
logger.info("Credential is valid.");
return true;
}
// Commandline usage -----------------------------------------------------------
async function main() {
// Websocket URLs of public servers
const NETWORKS = {
devnet: "wss://s.devnet.rippletest.net:51233",
testnet: "wss://s.altnet.rippletest.net:51233",
mainnet: "wss://xrplcluster.com/",
};
// Parse arguments ---------------------------------------------------------
let result = false
const program = new Command();
program
.name("verify-credential")
.description("Verify an XRPL credential")
.argument("[issuer]", "Credential issuer address as base58", "rEzikzbnH6FQJ2cCr4Bqmf6c3jyWLzkonS")
.argument("[subject]", "Credential subject (holder) address as base58", "rsYhHbanGpnYe3M6bsaMeJT5jnLTfDEzoA")
.argument("[credential_type]", "Credential type as string.", "my_credential")
.option("-b, --binary", "Use binary (hexadecimal) for credential_type")
.option(
`-n, --network <network> {${Object.keys(NETWORKS)}}`,
"Use the specified network for lookup",
(value) => {
if (!Object.keys(NETWORKS).includes(value)) {
throw new Error(`Must be one of: ${Object.keys(NETWORKS)}`);
}
return value;
},
"devnet"
)
.option("-q, --quiet", "Don't print log messages")
// Call verify_credential with appropriate args ----------------------------
.action(async (issuer, subject, credentialType, options) => {
const client = new Client(NETWORKS[options.network]);
await client.connect();
// Use INFO level by default when called from the commandline.
if (!options.quiet) { logger.level = "info" }
// Commander.js automatically sets options.binary to a boolean:
// - If you provide -b or --binary on the command line then options.binary = true
// - If you do not provide it then options.binary = false
result = await verifyCredential(client, issuer, subject, credentialType, options.binary);
await client.disconnect();
});
await program.parseAsync(process.argv);
// Return a nonzero exit code if credential verification failed -----------
if (!result) {
process.exit(1);
if (new Date(closeTime) > new Date(expirationTime)) {
console.log("Credential is expired.")
process.exit(3)
}
}
main().catch((err) => {
console.error("Fatal startup error:", err);
process.exit(1);
});
// Credential has passed all checks -------------------------------------------
console.log("Credential is valid.")
client.disconnect()

View File

@@ -11,12 +11,13 @@ export const frontmatter = {
},
};
const target = { prefix: "" }; // TODO: fixme
const categories = {
general: "General",
release_notes: "Release Notes",
advisories: "Advisories",
amendments: "Amendments",
case_study: "Case Study",
development: "Development",
developer_reflections: "Developer Reflections",
features: "Features",
@@ -88,7 +89,7 @@ export default function Index() {
<div className="col">
<div className="text-bg">
<h4 className="mb-3 eyebrow text-uppercase font-weight-light">
<span className="hero-post-date pb-2">
<span className="post-date pb-2">
{moment(heroPost.date).format(translate("blog.banner.date.part1","MMM"))}
</span>
{translate("blog.banner.date.part2", " ")}
@@ -134,14 +135,14 @@ export default function Index() {
className={`blog-filter input_${item}`}
type="checkbox"
name="categories"
id={`input_desktop_${item}`}
id={`input_${item}`}
defaultValue={`${item}`}
onChange={() => toggleCategory(item)}
defaultChecked
/>
<label
className="font-weight-bold"
htmlFor={`input_desktop_${item}`}
htmlFor={`input_${item}`}
>
{translate(categories[item])}
</label>
@@ -172,14 +173,14 @@ export default function Index() {
className={`blog-filter input_${item}`}
type="checkbox"
name="categories"
id={`input_mobile_${item}`}
id={`input_${item}`}
defaultValue={`${item}`}
onChange={() => toggleCategory(item)}
defaultChecked
/>
<label
className="font-weight-bold"
htmlFor={`input_mobile_${item}`}
htmlFor={`input_${item}`}
>
{translate(categories[item])}
</label>
@@ -199,9 +200,10 @@ export default function Index() {
className={`${card.category_id} pb-5 px-lg-4`}
id={card.title + i}
>
<div className="mb-4 category-list">
<div className="mb-4" id="category-list">
<img
alt=""
alt="card block"
id={`${card.category_id}`}
className="mb-4"
/>
<div
@@ -211,7 +213,7 @@ export default function Index() {
</div>
</div>
<div>
<p className="mb-0 card-date">
<p id="card-date" className="mb-0">
{moment(card.date).format(translate("blog.card.date","MMM DD, YYYY"))}
{ card.author ? ` by ${card.author}` : ""}
</p>

View File

@@ -1,7 +1,3 @@
## Blog sidebar file. Reminder: blogs must use one of the hard-coded categories
## in their labels frontmatter, or they won't show up in the list below the
## latest post, and they won't have an image.
- group: Blog
groupTranslationKey: sidebar.blog
page: index.page.tsx

View File

@@ -21,8 +21,8 @@
[AMMWithdraw transaction]: /docs/references/protocol/transactions/types/ammwithdraw.md
[AMMWithdraw transactions]: /docs/references/protocol/transactions/types/ammwithdraw.md
[AMMWithdraw]: /docs/references/protocol/transactions/types/ammwithdraw.md
[API v1]: /docs/references/http-websocket-apis/index.md#api-versioning
[API v2]: /docs/references/http-websocket-apis/index.md#api-versioning
[API v1]: /docs/references/http-websocket-apis/api-conventions/request-formatting.md#api-versioning
[API v2]: /docs/references/http-websocket-apis/api-conventions/request-formatting.md#api-versioning
[AccountDelete transaction]: /docs/references/protocol/transactions/types/accountdelete.md
[AccountDelete transactions]: /docs/references/protocol/transactions/types/accountdelete.md
[AccountDelete]: /docs/references/protocol/transactions/types/accountdelete.md
@@ -38,7 +38,6 @@
[Batch]: /docs/references/protocol/transactions/types/batch.md
[Batch transaction]: /docs/references/protocol/transactions/types/batch.md
[Batch transactions]: /docs/references/protocol/transactions/types/batch.md
[Bridge entry]: /docs/references/protocol/ledger-data/ledger-entry-types/bridge.md
[Check entry]: /docs/references/protocol/ledger-data/ledger-entry-types/check.md
[Check object]: /docs/references/protocol/ledger-data/ledger-entry-types/check.md
[CheckCancel transaction]: /docs/references/protocol/transactions/types/checkcancel.md
@@ -193,7 +192,6 @@
[Payment]: /docs/references/protocol/transactions/types/payment.md
[PermissionDelegation amendment]: /resources/known-amendments.md#permissiondelegation
[PermissionedDEX amendment]: /resources/known-amendments.md#permissioneddex
[Permissioned DEXes]: /docs/concepts/tokens/decentralized-exchange/permissioned-dexes.md
[PermissionedDomainSet transaction]: /docs/references/protocol/transactions/types/permissioneddomainset.md
[PermissionedDomainSetトランザクション]: /@l10n/ja/docs/references/protocol/transactions/types/permissioneddomainset.md
[PermissionedDomains amendment]: /resources/known-amendments.md#permissioneddomains
@@ -258,8 +256,6 @@
[XChainCreateBridge transaction]: /docs/references/protocol/transactions/types/xchaincreatebridge.md
[XChainCreateBridge transactions]: /docs/references/protocol/transactions/types/xchaincreatebridge.md
[XChainCreateBridge]: /docs/references/protocol/transactions/types/xchaincreatebridge.md
[XChainModifyBridge transaction]: /docs/references/protocol/transactions/types/xchainmodifybridge.md
[XChainModifyBridge transactions]: /docs/references/protocol/transactions/types/xchainmodifybridge.md
[XChainCreateClaimID transaction]: /docs/references/protocol/transactions/types/xchaincreateclaimid.md
[XChainCreateClaimID transactions]: /docs/references/protocol/transactions/types/xchaincreateclaimid.md
[XChainCreateClaimID]: /docs/references/protocol/transactions/types/xchaincreateclaimid.md

View File

@@ -1,6 +1,6 @@
---
seo:
description: Learn how XRPL Account Permission Delegation enables secure, granular control over your account transactions. Explore DelegateSet transactions for comprehensive permission and access management on the XRP Ledger.
description: XRPL accounts can delegate both transaction permissions and granular permissions to other accounts.
labels:
- Accounts
- Permissions
@@ -13,14 +13,14 @@ Permission delegation is the function of granting various permissions to another
_(Requires the [PermissionDelegation amendment][] {% not-enabled /%}.)_
## Background: The Need for Permission Delegation
## Background
Managing your [cryptographic keys](./cryptographic-keys.md) is one of the more challenging parts of using a blockchain. As part of a defense-in-depth strategy, a secure configuration should limit the damage that can occur if a secret key is compromised. One way to do this is to rotate keys regularly and to keep master keys off of computers that are always connected to the internet and serving user traffic. However, many use cases involve frequently and automatically signing transactions, which typically requires having secret keys on an internet-connected server.
Permission Delegation can reduce this problem by granting very limited permissions to separate accounts that have their keys available online for day-to-day tasks. Meanwhile, the keys with full control over the account can be kept offline, so that you only use them for special tasks, like issuing tokens. This is especially helpful when using compliance features like [Authorized Trust Lines](../tokens/fungible-tokens/authorized-trust-lines.md) that require a stablecoin issuer to individually approve each user after meeting regulatory requirements like Know Your Customer rules. With a proper configuration, you can minimize the consequences of a delegate's keys being compromized.
## How Permission Delegation Works
## How It Works
The account on whose behalf transactions are being sent is called the _delegator_. The account sending the transactions is called the _delegate_.
@@ -39,7 +39,7 @@ The delegate can only send transactions that match the permissions it has. Permi
For a complete list of transaction types that can or cannot be delegated as well as a list of granular permissions, see [Permission Values](/docs/references/protocol/data-types/permission-values.md).
### Limitations of Permission Delegation
### Limitations
The main limiting factor on how many delegates you can have is that you must hold enough XRP to meet the [reserve requirement](./reserves.md). Each delegate's permissions are tracked with a [Delegate ledger entry][], which counts as one item towards the delegator's owner reserve.

View File

@@ -12,11 +12,9 @@ Permissioned DEXes are controlled environments for trading within the XRP Ledger
There can be multiple permissioned DEXes within the XRP Ledger blockchain. Each one is uniquely associated with a permissioned domain, which acts as an allow-list for accessing that DEX. Trades placed within a permissioned DEX can only execute against other trades in the same permissioned DEX. Each permissioned DEX can have order books for any number of currency pairs, as needed.
## Background: The Need for Permissioned DEXes
## Background
The XRP Ledger has had a single, _open DEX_ since it launched. Anyone with an XRPL account can trade in this DEX, and the system automatically executes matching orders, also called offers, with no regard for who placed them. Orders also provide liquidity to cross-currency payments, which can potentially execute several trades as part of one atomic transaction.
Since the system inherently knows nothing about the people and organizations behind the accounts, there is no certainty who the counterparties are for any given trade. However, economic sanctions and financial regulations often place strict rules against transacting with criminals, terrorists, or specific countries. Given these limitations, regulated financial institutions may not be willing to take the risk of trading in the open DEX.
The XRP Ledger has had a single, _open DEX_ since it launched. Anyone with an XRPL account can trade in this DEX, and the system automatically executes matching orders, also called offers, with no regard for who placed them. Orders also provide liquidity to cross-currency payments, which can potentially execute several trades as part of one atomic transaction. Since the system inherently knows nothing about the people and organizations behind the accounts, there is no certainty who the counterparties are for any given trade. However, economic sanctions and financial regulations often place strict rules against transacting with criminals, terrorists, or specific countries. Given these limitations, regulated financial institutions may not be willing to take the risk of trading in the open DEX.
More background reading:
@@ -25,7 +23,7 @@ More background reading:
- [Permissioned Domains](./permissioned-domains.md)
## Key Roles in a Permissioned DEX
## Roles
To use a permissioned DEX, parties with the following roles and responsibilities need to exist:
@@ -40,28 +38,13 @@ It is possible for a single account to play more than one of these roles. For ex
_Figure: A permissioned order book, linked to a permissioned domain. Owen is both the domain owner and the issuer of one of the domain's accepted credentials. Tracy is able to trade in the permissioned order book because she holds an appropriate credential issued by Owen._
## Understanding the Permissioned DEX Structure: Offer Types and Interaction
## Structure
With the permissioned DEXes feature, a trade offer can be _open_, _permissioned_, or _hybrid_.
With the permissioned DEXes feature, a trade offer can be _open_, _permissioned_, or _hybrid_. An open offer uses the open DEX and can be matched by anyone else's open offer, hybrid offer, an [Automated Market Maker (AMM)](./automated-market-makers.md), or a combination of offers and an AMM. _Open offers_ are unchanged from how the XRPL's DEX works without permissioned DEXes.
### Open Offers
A permissioned offer specifies a domain ID, and is only valid if a permissioned domain with the matching ID exists and the account placing the offer has access to that domain because they hold the correct credentials. Permissioned offers are placed into an order book for the given domain and currency pair, separate from the open DEX's order book for that currency pair. Permissioned offers can only execute by matching other permissioned offers that specify the same domain ID. [Cross-currency payments](../../payment-types/cross-currency-payments.md) can also specify a domain ID, in which case they are restricted to only consuming offers from the corresponding permissioned DEX. Trades in a permissioned DEX can still use [auto-bridging](./autobridging.md) as long as the necessary orders all exist in the same permissioned DEX.
An open offer uses the open DEX and can be matched by anyone else's open offer, hybrid offer, an [Automated Market Maker (AMM)](./automated-market-makers.md), or a combination of offers and an AMM. _Open offers_ are unchanged from how the XRPL's DEX works without permissioned DEXes.
### Permissioned Offers
A permissioned offer specifies a domain ID and is only valid if a permissioned domain with the matching ID exists and the account placing the offer has access to that domain because they hold the correct credentials. Permissioned offers are placed into an order book for the given domain and currency pair, separate from the open DEX's order book for that currency pair.
Permissioned offers can only execute by matching other permissioned offers that specify the same domain ID. [Cross-currency payments](../../payment-types/cross-currency-payments.md) can also specify a domain ID, in which case they are restricted to only consuming offers from the corresponding permissioned DEX. Trades in a permissioned DEX can still use [auto-bridging](./autobridging.md) as long as the necessary orders all exist in the same permissioned DEX.
### Hybrid Offers
A hybrid offer specifies a domain ID and a flag marking it as hybrid. Like a permissioned offer, it is only valid if the specified permissioned domain exists and the account placing the offer has access to that domain. However, a hybrid offer can match offers in both the specified DEX and the open DEX.
Hybrid offers are tracked in both the open DEX order book and the domain-specific order book for their currency pair, and can be consumed by matching offers from either. When placed, they preferentially match offers from the permissioned DEX.
### How Open, Hybrid, and Permissioned Offers Match
A hybrid offer specifies a domain ID and a flag marking it as hybrid. Like a permissioned offer, it is only valid if the specified permissioned domain exists and the account placing the offer has access to that domain. However, a hybrid offer can match offers in both the specified DEX and the open DEX. Hybrid offers are tracked in both the open DEX order book and the domain-specific order book for their currency pair, and can be consumed by matching offers from either. When placed, they preferentially match offers from the permissioned DEX.
In summary, see the following table summarizing what offers can match:
@@ -71,9 +54,7 @@ In summary, see the following table summarizing what offers can match:
| Hybrid | ✅ | ✅ | ✅ (same domain) | ✅ |
| Permissioned | ❌ | ❌ | ✅ (same domain) | ❌ |
There is no single ledger entry to represent a given permissioned DEX: it implicitly exists as all the order books with the same domain ID. Order books with a given domain ID are created when valid offers are placed using that domain ID, and those order books are automatically deleted when they are empty.
A single transaction can use multiple order books with the same domain ID—in other words, different currency pairs in the same permissioned DEX—either as part of a longer [cross-currency payment](../../payment-types/cross-currency-payments.md) or through auto-bridging. A hybrid offer can match a mix of permissioned and open offers, but a transaction cannot use multiple different domains.
There is no single ledger entry to represent a given permissioned DEX: it implicitly exists as all the order books with the same domain ID. Order books with a given domain ID are implicitly created when valid offers are placed using that domain ID, and those order books are automatically deleted when they are empty. A single transaction can use multiple order books with the same domain ID—in other words, different currency pairs in the same permissioned DEX—either as part of a longer cross-currency payment or through auto-bridging. A hybrid offer can match a mix of permissioned and open offers, but a transaction cannot use multiple different domains.
The amount of liquidity and the best exchange rate available in any given DEX may vary depending on the offers placed in that DEX. Some traders may choose to trade in multiple permissioned DEXes and the open DEX to arbitrage price differences, while other traders may trade strictly in one domain, depending on their compliance requirements.
@@ -84,30 +65,20 @@ _Figure: The open DEX, and two different permissioned DEXes, each containing ord
### Invalid Permissioned Offers
In addition to the ways offers can be unfunded in the open DEX, offers in a permissioned DEX can become _invalid_. Invalid offers are treated the same way as unfunded offers and are automatically removed whenever a transaction modifies the order book containing them. They can remain in the ledger data indefinitely until a transaction removes them, but they cannot be executed if they are invalid.
Reasons a permissioned offer can become invalid include:
In addition to the ways offers can be unfunded in the open DEX, offers in a permissioned DEX can become _invalid_. Invalid offers are treated the same way as unfunded offers, and are automatically removed whenever a transaction modifies the order book containing them. They can remain in the ledger data indefinitely until a transaction removes them, but they cannot be executed if they are invalid. Reasons that a permissioned offer can become invalid include:
- A credential, held by the account placing the offer, has expired or has been deleted.
- The permissioned domain has been updated to change the set of credentials that grant access, and the account placing the offer does not hold any of the new credentials.
- The permissioned domain has been deleted.
Like with unfunded offers, it is possible for an offer to become temporarily invalid and then become valid again. For example, if a trader's credential that grants access to a permissioned domain expires, their offers in the corresponding permissioned DEX would be invalid; but if they get the credential renewed, any offers that hadn't already been removed automatically become valid again.
Like with unfunded offers, it is possible for an offer to become temporarily invalid, then become valid again. For example, if a trader's credential that grants access to a permissioned domain expires, their offers in the corresponding permissioned DEX would be invalid; but if they get the credential renewed, any offers that hadn't already been removed automatically become valid again.
### Limitations of Permissioned DEXes
### Limitations
The permissioned DEXes feature is enabled by the **PermissionedDEX** amendment, and relies on the [Credentials](../../decentralized-storage/credentials.md) and [Permissioned Domains](./permissioned-domains.md) amendments, so it cannot be used until _all_ of those amendments have been enabled.
#### Not Compatible with AMMs
Permissioned DEXes are incompatible with [Automated Market Makers (AMMs)](../../tokens/decentralized-exchange/automated-market-makers.md). Permissioned offers and permissioned payments cannot be filled by AMMs, and access to AMMs cannot be restricted by a permissioned domain. Trades that use the open DEX can sometimes consume a hybrid offer and use an AMM in the same transaction, but transactions that specify a domain cannot use any AMMs.
**Permissioned DEXes are independent**
Permissioned DEXes are incompatible with Automated Market Makers (AMMs). Permissioned offers and permissioned payments cannot be filled by AMMs, and access to AMMs cannot be restricted by a permissioned domain. Trades that use the open DEX can sometimes consume a hybrid offer and use an AMM in the same transaction, but transactions that specify a domain cannot use any AMMs.
Each permissioned DEX is separate, with its own order books and offers. A single transaction cannot trade in multiple permissioned DEXes or aggregate liquidity from multiple permissioned DEXes. Hybrid offers can use a mix of one permissioned DEX and the open DEX, but they cannot use multiple different permissioned DEXes.
#### Security Considerations for Permissioned DEXes
The security and fairness of a permissioned DEX depend on the owner of the permissioned domain and the issuers of credentials that grant access to it. At a baseline, the definition of each credential and the requirements for getting that credential are defined and enforced by the credential issuer, so the existence of a permissioned domain does not inherently mean anything about who is able to use it in practice.
A credential issuer can issue or revoke credentials at their discretion. If they are unreliable or compromised, so is any permissioned domain that accepts their credentials. Similarly, the domain owner can modify the domain's list of accepted credentials to grant or deny access to the domain arbitrarily, so if they are untrustworthy or compromised, the domain is as well.
The security and fairness of a permissioned DEX depend on the owner of the permissioned domain and the issuers of credentials that grant access to it. At a baseline, the definition of each credential and the requirements for getting that credential are defined and enforced by the credential issuer, so the existence of a permissioned domain does not inherently mean anything about who is able to use it in practice. A credential issuer can issue or revoke credentials at their discretion. If they are unreliable or compromised, so is any permissioned domain that accepts their credentials. Similarly, the domain owner can modify the domain's list of accepted credentials to grant or deny access to the domain arbitrarily, so if they are untrustworthy or compromised, the domain is as well.

View File

@@ -1,13 +1,13 @@
---
seo:
description: Learn how Permissioned Domains on the XRP Ledger enable controlled, secure blockchain environments. Explore their role in decentralized exchanges (DEXes) and lending protocols.
description: The definition and details of a Permissioned Domain instance.
labels:
- Compliance
- Permissioned Domains
---
# Permissioned Domains
Permissioned domains are controlled environments within the broader ecosystem of the XRP Ledger blockchain. Domains do nothing on their own, but features such as [Permissioned DEXes][] and Lending Protocols can use domains to restrict and manage access, so traditional financial institutions can offer services on chain while complying with various compliance rules.
Permissioned domains are controlled environments within the broader ecosystem of the XRP Ledger blockchain. Domains do nothing on their own, but features such as Permissioned DEXes and Lending Protocols can use domains to restrict access, so that traditional financial institutions can offer services on chain while complying with various compliance rules.
The only configurable rule for a domain is the set of accepted [credentials][]. Future amendments may add new and different types of rules to encompass any limits that a financial institution may need to follow to maintain compliance with the laws of the jurisdictions where they do business.
@@ -29,7 +29,7 @@ A domain serves as an abstraction layer between credentials and a resource being
Users do not need to apply to join or leave a domain. When a transaction requires access to a resource that is restricted by a domain, the transaction automatically checks if the account holds a credential matching that domain's accepted credentials, and fails if they have none. The user's credential must be accepted and not expired.
## Uses for Permissioned Domains
## Uses for Domains
Currently, there are no available XRP Ledger features that use permissioned domains. However, amendments that are in development and use domains include:

View File

@@ -1,6 +1,5 @@
---
seo:
description: Learn about multi-purpose tokens (MPTs) on XRP Ledger. MPTs are a flexible way to issue fungible tokens with built-in metadata, compliance, and transfer controls.
blurb: Multi-purpose tokens offer a more compact, flexible token type than trust lines.
labels:
- Tokens
- MPTs
@@ -11,78 +10,48 @@ status: not_enabled
_(Requires the [MPTokensV1 amendment][] {% not-enabled /%})_
Multi-purpose tokens (MPTs) are a more compact and flexible type of [fungible token](./index.md) on the XRP Ledger.
Multi-purpose tokens (MPTs) are a more compact and flexible type of fungible token.
MPTs let you take advantage of ready-to-use tokenization features with a few lines of code. You can create many token experiences from one token program itself.
## Key Features of MPTs on XRPL
The following are notable features of MPTs on XRPL.
**On-Chain Metadata Storage**
MPTs let you take advantage of ready-to-use tokenization features with a few lines of code. You can create many token experiences from one token program itself. Notable features include:
- MPTs store their metadata directly on the XRPL blockchain. Once set, the metadata is immutable.
- A 1024-byte URI field provides a metadata pointer that allows you to use an off-chain source for metadata in addition to the on-chain source. This lets your application access necessary information directly from the chain, prompting higher interoperability for tokens, without losing the ability to attach additional information.
**Transferability and Supply Controls**
- MPTs can have a fixed token supply where you set a cap on the maximum number of tokens that can be minted.
- You can define MPTs as non-transferable, tokens that can only be transferred back to the issuer, but not among tokenholders. Useful for cases such as issuing airline credits or loyalty rewards.
- Issuers can set transfer fees to collect on-chain revenue each time the token is traded among tokenholders.
**Built-In Compliance Features**
MPTs also have advanced compliance features, including:
- The ability to lock tokens held by a tokenholder to support compliance requirements.
- The ability to set a global lock for all MPT balances across all tokenholders.
- The issuer can configure MPTs that can be clawed back from tokenholder wallets, either to revoke them, or to reassign them in the case of lost wallet keys.
- An opt-in feature can allow only wallets authorized by the issuer to hold issued tokens.
- MPTs also have advanced compliance features:
- The ability to lock tokens held by a tokenholder to support compliance requirements.
- The ability to set a global lock for all MPT balances across all tokenholders.
- The issuer can configure MPTs that can be clawed back from tokenholder wallets, either to revoke them, or to reassign them in the case of lost wallet keys.
- An opt-in feature can allow only wallets authorized by the issuer to hold issued tokens.
## MPTs versus Trust Lines
These are the primary differences between MPTs and [trust lines](/docs/concepts/tokens/fungible-tokens#trust-lines).
Unlike trust lines, MPTs do not represent bidirectional debt relationships. Instead, MPTs function more like a unidirectional trust line with only one balance. This reduces the overhead to support common tokenization requirements, including non-monetary use cases such as tracking reputation points in an online game.
**Conceptual Differences**
MPTs offer a less complicated conceptual model than trust lines.
- Unlike trust lines, MPTs do not represent bidirectional debt relationships. Instead, MPTs function more like a unidirectional trust line with only one balance. This reduces the overhead to support common tokenization requirements, including non-monetary use cases such as tracking reputation points in an online game.
MPTs require significantly less space than trust lines. They require roughly 52 bytes for each MPT held by a token holder, compared to at least 234 bytes for every new trust line.
- MPTs offer a less complicated conceptual model than trust lines.
They reduce the long-term infrastructure and storage burdens for node operators, increasing network resiliency.
**Ledger Storage and Performance**
MPTs also improve node perfomance when processing large volumes of transactions.
- MPTs require significantly less space than trust lines. They require roughly 52 bytes for each MPT held by a token holder, compared to at least 234 bytes for every new trust line.
MPTs are unidirectional. While trust lines use "balance netting," MPTs have only a single balance.
- They reduce the long-term infrastructure and storage burdens for node operators, increasing network resiliency.
An account can issue a maximum of 32 unique MPT issuances. If an issuer wants to support more than this number of MPTs, they can open additional accounts.
- MPTs also improve node perfomance when processing large volumes of transactions.
Since token holders will not acquire an MPT without first making an off-ledger trust decision, MPTs have no trust limits. For example, a common use case for an MPT is a fiat-backed stablecoin, where a token holder wouldn't purchase more stablecoins than they would feel comfortable holding.
**Transfer Logic and Directionality**
- MPTs are unidirectional. While trust lines use "balance netting," MPTs have only a single balance.
- An account can issue a maximum of 32 unique MPT issuances. If an issuer wants to support more than this number of MPTs, they can open additional accounts.
- Since token holders will not acquire an MPT without first making an off-ledger trust decision, MPTs have no trust limits. For example, a common use case for an MPT is a [fiat-backed stablecoin](/docs/concepts/tokens/fungible-tokens/stablecoins#fiat-backed), where a token holder wouldn't purchase more stablecoins than they would feel comfortable holding.
- Unlike some existing capabilities of the ledger, MPTs are not subject to [rippling](/docs/concepts/tokens/fungible-tokens/rippling) and do not require configurability settings related to that functionality.
Unlike some existing capabilities of the ledger, MPTs are not subject to rippling, and do not require configurability settings related to that functionality.
## MPTs versus IOUs
MPTs are different from IOUs in the following ways.
On a technical level, MPTs provide a fundamentally different way to represent fungible tokens on the ledger. While IOUs are represented by trustlines and have bilateral debt relationships, MPTs use a simpler, unilateral relationship captured by an MPToken object. This results in substantial space savings on the ledger. The representation of a fungible token as a token object instead of a trustline makes it easier to enable functionality for real-world financial assets on-chain, such as token-level metadata, fixed supply, and fixed-point balance.
**Technical Representation on the Ledger**
On a usage level, MPTs provide a straightforward conceptual model compared to trustlines and rippling. Developers can more easily build web3 applications around `MPToken` and `MPTokenIssuance` objects, with some similarities to the conceptual model of XLS-20 NFTs. It is also simpler for ordinary users to understand what tokens are available, what tokens they have issued, and what they hold in their wallet. For both issuers and holders of MPTs, there will typically be a smaller XRP reserve compared to the equivalent representations with IOU trustlines.
On a technical level, MPTs provide a fundamentally different way to represent fungible tokens on the ledger. While IOUs are represented by trustlines and have bilateral debt relationships, MPTs use a simpler, unilateral relationship captured by an MPToken object. This results in substantial space savings on the ledger.
The representation of a fungible token as a token object instead of a trustline makes it easier to enable functionality for real-world financial assets on-chain, such as token-level metadata, fixed supply, and fixed-point balance.
**Developer Experience and App Design**
On a usage level, MPTs provide a straightforward conceptual model compared to [trustlines](/docs/concepts/tokens/fungible-tokens#trust-lines) and [rippling](/docs/concepts/tokens/fungible-tokens/rippling). Developers can more easily build web3 applications around `[MPToken](/docs/references/protocol/ledger-data/ledger-entry-types/mptoken)` and `[MPTokenIssuance](/docs/references/protocol/ledger-data/ledger-entry-types/mptokenissuance)` objects, with some similarities to the conceptual model of XLS-20 NFTs.
It is also simpler for ordinary users to understand what tokens are available, what tokens they have issued, and what they hold in their wallet.
For both issuers and holders of MPTs, there will typically be a smaller XRP reserve compared to the equivalent representations with IOU trustlines.
## Use Case and Long-Term Considerations
MPTs are intended to be complementary to IOUs. While there might be use cases where either MPTs or IOUs might be suitable, there will likely be a need for both over the long term. There will be use cases such as credit lines for lending and borrowing that might be better represented by IOUs long term. The MPT feature set should evolve in an incremental manner to unlock more common use cases first and deliver additional feature support at a later time. During the MPT development period, some cases might still be better represented by an IOU, and then later be better supported with MPTs.
MPTs are intended to be complementary to IOUs. While there might be use cases where either MPTs or IOUs might be suitable, there will likely be a need for both over the long term. There will be use cases such as credit lines for lending and borrowing that might be better represented by IOUs long term. The MPT feature set should evolve in an incremental manner to unlock more common use cases first and deliver additional feature support at a later time. During the MPT development period, some cases might still be better represented by an IOU, then later be better supported with MPTs.
## See Also

View File

@@ -1,6 +1,6 @@
---
seo:
description: Discover how XRPL Batch Transactions streamline multiple blockchain operations into a single secure transaction. Learn about batch modes, execution details, and security considerations.
description: Batch allows up to 8 transactions to be submitted as a single unit.
labels:
- Batch
- Transactions
@@ -8,9 +8,7 @@ status: not_enabled
---
# Batch Transactions
XRPL Batch Transactions let you package multiple [transactions](/docs/concepts/transactions) together and execute them as a single unit. It eliminates the risk of partial completion and unexpected outcomes, giving you a more reliable and predictable experience for complex operations. Up to eight transactions can be submitted in a single batch.
## XRPL Batch Use Cases
`Batch` lets you package multiple transactions together and execute them as a single unit. It eliminates the risk of partial completion and unexpected outcomes, giving you a more reliable and predictable experience for complex operations. Up to eight transactions can be submitted in a single batch.
Some potential uses for `Batch` include the following.
- All or nothing: You can mint an NFT and create an offer for it in one transaction. If the offer creation fails, the NFT mint is reverted as well.
@@ -21,11 +19,7 @@ Some potential uses for `Batch` include the following.
`Batch` transactions are comprised of the _outer transaction_, the wrapper `Batch` transaction itself, and the _inner transactions_, each of which is executed atomically. The precise way that the inner transactions are processed is determined by the batch _mode_.
<div align="center">
<iframe width="560" height="315" src="https://www.youtube.com/embed/LsMMXm7jm1k" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>
</div>
## XRPL Batch Transaction Modes
## Batch Mode
There are four possible batch modes: `ALLORNOTHING`, `ONLYONE`, `UNTILFAILURE`, and `INDEPENDENT`.
@@ -45,9 +39,9 @@ In `ALLORNOTHING` mode, all inner transactions must succeed for any one of them
All transactions are applied, even if one or more of the inner transactions fail.
## XRPL Raw Transactions Object
## Raw Transactions
The `RawTransactions` object is a container for the list of transactions to be applied. You can include up to eight transactions in a single batch. The transactions can come from one account or multiple accounts.
The `RawTransactions` object is a container for the list of transactions to be applied. You can include up to eight transactions in a sincle batch. The transactions can come from one account or multiple accounts.
Each inner transaction:
@@ -73,8 +67,6 @@ This field is included if the account is signing with multi-sign (as opposed to
This field must be provided if more than one account has inner transactions included in the Batch. In that case, this field must contain signatures from all accounts whose inner transactions are included, excluding the account signing the outer transaction (if applicable).
#### Fields Used for XRPL Batch Transactions
Each object in this array contains the following fields:
| Field Name | Required? | JSON Type | Internal Type |
@@ -98,7 +90,7 @@ These fields are included if the account is signing with a single signature (as
This field is included if the account is signing with multi-sign (as opposed to a single signature). It operates equivalently to the `Signers` field used in standard transaction multi-sign. This field holds the signatures for the `Flags` field and the hashes of the transactions in `RawTransactions`.
## XRPL Batch Transaction Fees
## Transaction Fee
The fee for the outer transaction is twice the base fee (a total of 20 drops when there is no fee escalation), plus the sum of the transaction fees of all the inner transactions (which incorporates factors like higher fees for `multisign` or `AMMCreate`), plus an additional base fee amount for each additional signature in the transaction (for example, from `BatchSigners`). Expressed as an equation:
@@ -132,7 +124,7 @@ There is also a pointer back to the parent outer transaction (`ParentBatchID`).
## Transaction Common Fields
This standard doesn't add any new fields to the [transaction common fields](/docs/references/protocol/transactions/common-fields.md), but it does add another global transaction flag:
This standard doesn't add any new fields to the transaction common fields, but it does add another global transaction flag:
| Flag Name | Value |
|-----------------|------------|
@@ -140,7 +132,7 @@ This standard doesn't add any new fields to the [transaction common fields](/doc
This flag should be used only if a transaction is an inner transaction in a `Batch` transaction. This signifies that the transaction shouldn't be signed. Any normal transaction that includes this flag should be rejected.
## Security for XRPL Batch Transactions
## Security
Batch transactions come with additional security considerations.

View File

@@ -1,168 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<diagram program="umlet" version="14.2">
<zoom_level>10</zoom_level>
<element>
<id>UMLUseCase</id>
<coordinates>
<x>230</x>
<y>90</y>
<w>400</w>
<h>360</h>
</coordinates>
<panel_attributes/>
<additional_attributes/>
</element>
<element>
<id>UMLUseCase</id>
<coordinates>
<x>30</x>
<y>90</y>
<w>400</w>
<h>360</h>
</coordinates>
<panel_attributes/>
<additional_attributes/>
</element>
<element>
<id>Text</id>
<coordinates>
<x>140</x>
<y>50</y>
<w>110</w>
<h>30</h>
</coordinates>
<panel_attributes>*rippled Server*</panel_attributes>
<additional_attributes/>
</element>
<element>
<id>Text</id>
<coordinates>
<x>400</x>
<y>50</y>
<w>110</w>
<h>30</h>
</coordinates>
<panel_attributes>*Clio Server*</panel_attributes>
<additional_attributes/>
</element>
<element>
<id>Text</id>
<coordinates>
<x>310</x>
<y>70</y>
<w>50</w>
<h>30</h>
</coordinates>
<panel_attributes>*Both*</panel_attributes>
<additional_attributes/>
</element>
<element>
<id>Text</id>
<coordinates>
<x>290</x>
<y>250</y>
<w>100</w>
<h>50</h>
</coordinates>
<panel_attributes>style=wordwrap
• Serve most API methods</panel_attributes>
<additional_attributes/>
</element>
<element>
<id>Text</id>
<coordinates>
<x>430</x>
<y>150</y>
<w>140</w>
<h>50</h>
</coordinates>
<panel_attributes>style=wordwrap
• Scales efficiently to many requests</panel_attributes>
<additional_attributes/>
</element>
<element>
<id>Text</id>
<coordinates>
<x>30</x>
<y>0</y>
<w>490</w>
<h>40</h>
</coordinates>
<panel_attributes>fontsize=20
*API functionality provided by servers*</panel_attributes>
<additional_attributes/>
</element>
<element>
<id>Text</id>
<coordinates>
<x>90</x>
<y>160</y>
<w>150</w>
<h>50</h>
</coordinates>
<panel_attributes>style=wordwrap
• Provides Admin API methods</panel_attributes>
<additional_attributes/>
</element>
<element>
<id>Text</id>
<coordinates>
<x>70</x>
<y>220</y>
<w>150</w>
<h>80</h>
</coordinates>
<panel_attributes>style=wordwrap
• Provides pending / unvalidated data including transaction queue
</panel_attributes>
<additional_attributes/>
</element>
<element>
<id>Text</id>
<coordinates>
<x>80</x>
<y>300</y>
<w>160</w>
<h>70</h>
</coordinates>
<panel_attributes>style=wordwrap
• Has a live view of consensus and peer-to-peer network</panel_attributes>
<additional_attributes/>
</element>
<element>
<id>Text</id>
<coordinates>
<x>440</x>
<y>200</y>
<w>180</w>
<h>70</h>
</coordinates>
<panel_attributes>style=wordwrap
• Provides NFT methods: nft_history, nft_info, nfts_by_issuer</panel_attributes>
<additional_attributes/>
</element>
<element>
<id>Text</id>
<coordinates>
<x>450</x>
<y>270</y>
<w>180</w>
<h>50</h>
</coordinates>
<panel_attributes>style=wordwrap
• Provides mpt_holders method</panel_attributes>
<additional_attributes/>
</element>
<element>
<id>Text</id>
<coordinates>
<x>430</x>
<y>320</y>
<w>140</w>
<h>80</h>
</coordinates>
<panel_attributes>style=wordwrap
• Serves rippled-exclusive API requests by forwarding</panel_attributes>
<additional_attributes/>
</element>
</diagram>

View File

@@ -1,138 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE svg PUBLIC '-//W3C//DTD SVG 1.0//EN'
'http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd'>
<svg fill-opacity="1" xmlns:xlink="http://www.w3.org/1999/xlink" color-rendering="auto" color-interpolation="auto" text-rendering="auto" stroke="black" stroke-linecap="square" width="640" stroke-miterlimit="10" shape-rendering="auto" stroke-opacity="1" fill="black" stroke-dasharray="none" font-weight="normal" stroke-width="1" viewBox="10 -20 640 490" height="490" xmlns="http://www.w3.org/2000/svg" font-family="'Dialog'" font-style="normal" stroke-linejoin="miter" font-size="12px" stroke-dashoffset="0" image-rendering="auto"
><!--Generated by the Batik Graphics2D SVG Generator--><defs id="genericDefs"
/><g
><defs id="defs1"
><clipPath clipPathUnits="userSpaceOnUse" id="clipPath1"
><path d="M0 0 L2147483647 0 L2147483647 2147483647 L0 2147483647 L0 0 Z"
/></clipPath
><clipPath clipPathUnits="userSpaceOnUse" id="clipPath2"
><path d="M0 0 L0 80 L140 80 L140 0 Z"
/></clipPath
><clipPath clipPathUnits="userSpaceOnUse" id="clipPath3"
><path d="M0 0 L0 50 L180 50 L180 0 Z"
/></clipPath
><clipPath clipPathUnits="userSpaceOnUse" id="clipPath4"
><path d="M0 0 L0 70 L180 70 L180 0 Z"
/></clipPath
><clipPath clipPathUnits="userSpaceOnUse" id="clipPath5"
><path d="M0 0 L0 70 L160 70 L160 0 Z"
/></clipPath
><clipPath clipPathUnits="userSpaceOnUse" id="clipPath6"
><path d="M0 0 L0 80 L150 80 L150 0 Z"
/></clipPath
><clipPath clipPathUnits="userSpaceOnUse" id="clipPath7"
><path d="M0 0 L0 50 L150 50 L150 0 Z"
/></clipPath
><clipPath clipPathUnits="userSpaceOnUse" id="clipPath8"
><path d="M0 0 L0 40 L490 40 L490 0 Z"
/></clipPath
><clipPath clipPathUnits="userSpaceOnUse" id="clipPath9"
><path d="M0 0 L0 50 L140 50 L140 0 Z"
/></clipPath
><clipPath clipPathUnits="userSpaceOnUse" id="clipPath10"
><path d="M0 0 L0 50 L100 50 L100 0 Z"
/></clipPath
><clipPath clipPathUnits="userSpaceOnUse" id="clipPath11"
><path d="M0 0 L0 30 L50 30 L50 0 Z"
/></clipPath
><clipPath clipPathUnits="userSpaceOnUse" id="clipPath12"
><path d="M0 0 L0 30 L110 30 L110 0 Z"
/></clipPath
><clipPath clipPathUnits="userSpaceOnUse" id="clipPath13"
><path d="M0 0 L0 360 L400 360 L400 0 Z"
/></clipPath
></defs
><g font-family="sans-serif" font-size="14px" transform="translate(430,320)"
><text x="5" xml:space="preserve" y="18.3594" clip-path="url(#clipPath2)" stroke="none"
>• Serves</text
><text x="5" xml:space="preserve" y="34.7188" clip-path="url(#clipPath2)" stroke="none"
>rippled-exclusive</text
><text x="5" xml:space="preserve" y="51.0781" clip-path="url(#clipPath2)" stroke="none"
>API requests by</text
><text x="5" xml:space="preserve" y="67.4375" clip-path="url(#clipPath2)" stroke="none"
>forwarding</text
></g
><g font-family="sans-serif" font-size="14px" transform="translate(450,270)"
><text x="5" xml:space="preserve" y="18.3594" clip-path="url(#clipPath3)" stroke="none"
>• Provides mpt_holders</text
><text x="5" xml:space="preserve" y="34.7188" clip-path="url(#clipPath3)" stroke="none"
>method</text
></g
><g font-family="sans-serif" font-size="14px" transform="translate(440,200)"
><text x="5" xml:space="preserve" y="18.3594" clip-path="url(#clipPath4)" stroke="none"
>• Provides NFT methods:</text
><text x="5" xml:space="preserve" y="34.7188" clip-path="url(#clipPath4)" stroke="none"
>nft_history, nft_info,</text
><text x="5" xml:space="preserve" y="51.0781" clip-path="url(#clipPath4)" stroke="none"
>nfts_by_issuer</text
></g
><g font-family="sans-serif" font-size="14px" transform="translate(80,300)"
><text x="5" xml:space="preserve" y="18.3594" clip-path="url(#clipPath5)" stroke="none"
>• Has a live view of</text
><text x="5" xml:space="preserve" y="34.7188" clip-path="url(#clipPath5)" stroke="none"
>consensus and</text
><text x="5" xml:space="preserve" y="51.0781" clip-path="url(#clipPath5)" stroke="none"
>peer-to-peer network</text
></g
><g font-family="sans-serif" font-size="14px" transform="translate(70,220)"
><text x="5" xml:space="preserve" y="18.3594" clip-path="url(#clipPath6)" stroke="none"
>• Provides pending /</text
><text x="5" xml:space="preserve" y="34.7188" clip-path="url(#clipPath6)" stroke="none"
>unvalidated data</text
><text x="5" xml:space="preserve" y="51.0781" clip-path="url(#clipPath6)" stroke="none"
>including</text
><text x="5" xml:space="preserve" y="67.4375" clip-path="url(#clipPath6)" stroke="none"
>transaction queue</text
></g
><g font-family="sans-serif" font-size="14px" transform="translate(90,160)"
><text x="5" xml:space="preserve" y="18.3594" clip-path="url(#clipPath7)" stroke="none"
>• Provides Admin</text
><text x="5" xml:space="preserve" y="34.7188" clip-path="url(#clipPath7)" stroke="none"
>API methods</text
></g
><g font-size="20px" font-weight="bold" font-family="sans-serif" transform="translate(30,0)"
><text x="5" xml:space="preserve" y="24.0781" clip-path="url(#clipPath8)" stroke="none"
>API functionality provided by servers</text
></g
><g font-family="sans-serif" font-size="14px" transform="translate(430,150)"
><text x="5" xml:space="preserve" y="18.3594" clip-path="url(#clipPath9)" stroke="none"
>• Scales efficiently</text
><text x="5" xml:space="preserve" y="34.7188" clip-path="url(#clipPath9)" stroke="none"
>to many requests</text
></g
><g font-family="sans-serif" font-size="14px" transform="translate(290,250)"
><text x="5" xml:space="preserve" y="18.3594" clip-path="url(#clipPath10)" stroke="none"
>• Serve most</text
><text x="5" xml:space="preserve" y="34.7188" clip-path="url(#clipPath10)" stroke="none"
>API methods</text
></g
><g font-size="14px" font-weight="bold" font-family="sans-serif" transform="translate(310,70)"
><text x="5" xml:space="preserve" y="18.3594" clip-path="url(#clipPath11)" stroke="none"
>Both</text
></g
><g font-size="14px" font-weight="bold" font-family="sans-serif" transform="translate(400,50)"
><text x="5" xml:space="preserve" y="18.3594" clip-path="url(#clipPath12)" stroke="none"
>Clio Server</text
></g
><g font-size="14px" font-weight="bold" font-family="sans-serif" transform="translate(140,50)"
><text x="5" xml:space="preserve" y="18.3594" clip-path="url(#clipPath12)" stroke="none"
>rippled Server</text
></g
><g fill="rgb(255,255,255)" fill-opacity="0" transform="translate(30,90)" stroke-opacity="0" stroke="rgb(255,255,255)"
><ellipse rx="199.25" ry="179.25" clip-path="url(#clipPath13)" cx="199.75" cy="179.75" stroke="none"
/></g
><g transform="translate(30,90)"
><ellipse rx="199.25" fill="none" ry="179.25" clip-path="url(#clipPath13)" cx="199.75" cy="179.75"
/></g
><g fill="rgb(255,255,255)" fill-opacity="0" transform="translate(230,90)" stroke-opacity="0" stroke="rgb(255,255,255)"
><ellipse rx="199.25" ry="179.25" clip-path="url(#clipPath13)" cx="199.75" cy="179.75" stroke="none"
/></g
><g transform="translate(230,90)"
><ellipse rx="199.25" fill="none" ry="179.25" clip-path="url(#clipPath13)" cx="199.75" cy="179.75"
/></g
></g
></svg
>

Before

Width:  |  Height:  |  Size: 7.5 KiB

View File

@@ -1,39 +0,0 @@
# Short Names of Ledger Entries
Some API methods, specifically the [account_objects method][] and [ledger_data method][], allow filtering the ledger entries they return based on the type of ledger entry. The type field you specify can use either the canonical name of the [ledger entry](../../protocol/ledger-data/ledger-entry-types/index.md) or a short name, as in the following table.
The "Ownable" column indicates whether the ledger entry type can appear in owner directories. Ledger entries that are not ownable cannot appear in `account_objects` responses and cannot be used as a `type` filter in that method.
| Canonical Name | Short Name | Ownable | Related Amendment |
| -------------------- | --------------------- | ------- |---|
| `AccountRoot` | `account` | No | |
| `Amendments` | `amendments` | No | |
| `AMM` | `amm` | No | {% amendment-disclaimer name="AMM" compact=true /%} |
| `Bridge` | `bridge` | Yes | {% amendment-disclaimer name="XChainBridge" compact=true /%} |
| `Check` | `check` | Yes | {% amendment-disclaimer name="Checks" compact=true /%} |
| `Credential` | `credential` | Yes | {% amendment-disclaimer name="Credentials" compact=true /%} |
| `Delegate` | `delegate` | Yes | {% amendment-disclaimer name="PermissionDelegation" compact=true /%} |
| `DepositPreauth` | `deposit_preauth` | Yes | {% amendment-disclaimer name="DepositPreauth" compact=true /%} |
| `DID` | `did` | Yes | {% amendment-disclaimer name="DID" compact=true /%} |
| `DirectoryNode` | `directory` | No | |
| `Escrow` | `escrow` | Yes | |
| `FeeSettings` | `fee` | No | |
| `LedgerHashes` | `hashes` | No | |
| `MPToken` | `mptoken` | Yes | {% amendment-disclaimer name="MPTokensV1" compact=true /%} |
| `MPTokenIssuance` | `mpt_issuance` | Yes | {% amendment-disclaimer name="MPTokensV1" compact=true /%} |
| `NegativeUNL` | `nunl` | No | {% amendment-disclaimer name="NegativeUNL" compact=true /%} |
| `NFTokenOffer` | `nft_offer` | Yes | {% amendment-disclaimer name="NonFungibleTokensV1_1" compact=true /%} |
| `NFTokenPage` | `nft_page` | Yes | {% amendment-disclaimer name="NonFungibleTokensV1_1" compact=true /%} |
| `Offer` | `offer` | Yes | |
| `Oracle` | `oracle` | Yes | {% amendment-disclaimer name="PriceOracle" compact=true /%} |
| `PayChannel` | `payment_channel` | Yes | |
| `PermissionedDomain` | `permissioned_domain` | Yes | {% amendment-disclaimer name="PermissionedDomains" compact=true /%} |
| `RippleState` | `state` | Yes | |
| `SignerList` | `signer_list` | Yes | |
| `Ticket` | `ticket` | Yes | {% amendment-disclaimer name="TicketBatch" compact=true /%} |
| `XChainOwnedClaimID` | `xchain_owned_claim_id` | Yes | {% amendment-disclaimer name="XChainBridge" compact=true /%} |
| `XChainOwnedCreate`<wbr>`AccountClaimID` | `xchain_owned_`<wbr>`create_account_claim_id` | Yes | {% amendment-disclaimer name="XChainBridge" compact=true /%} |
<!-- Author's note: used <wbr> (word break opportunity) so that the long xchain names don't cause the table to scroll horizontally. -->
{% raw-partial file="/docs/_snippets/common-links.md" /%}

View File

@@ -1,4 +1,6 @@
---
html: request-formatting.html
parent: api-conventions.html
seo:
description: Standard request format, with examples, for the WebSocket, JSON-RPC, and Commandline interfaces.
---
@@ -11,11 +13,12 @@ seo:
{% tab label="WebSocket" %}
```json
{
"id": "example_ws_request_1",
"id": 2,
"command": "account_info",
"account": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59",
"strict": true,
"ledger_index": "validated",
"api_version": 2
"api_version": 1
}
```
{% /tab %}
@@ -30,8 +33,9 @@ Content-Type: application/json
"params": [
{
"account": "r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59",
"strict": true,
"ledger_index": "validated",
"api_version": 2
"api_version": 1
}
]
}
@@ -40,7 +44,7 @@ Content-Type: application/json
{% tab label="Commandline" %}
```sh
rippled account_info r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59 validated
rippled account_info r9cZA1mLK5R5Am25ArfXFmqgNwjZgnfk59 validated strict
```
{% /tab %}
@@ -55,7 +59,7 @@ After you open a WebSocket to the `rippled` server, you can send commands as a [
|:--------------------|:----------|:-------------------------------------------|
| `command` | String | The name of the [API method](../public-api-methods/index.md). |
| `id` | (Various) | _(Optional)_ A unique value to identify this request. The response to this request uses the same `id` field. This way, even if responses arrive out of order, you know which request prompted which response. |
| `api_version` | Number | _(Optional)_ The API version to use. For details, see [API Versioning](../index.md#api-versioning). |
| `api_version` | Number | _(Optional)_ The API version to use. If omitted, uses version 1. For details, see [API Versioning](#api-versioning). |
| (Method Parameters) | (Various) | Provide any parameters to the method at the top level. |
See [Response Formatting](response-formatting.md) for the response from the server.
@@ -80,7 +84,7 @@ The object inside the `params` array can contain the following fields:
| Field | Type | Description |
|:--------------------|:----------|:-------------------------------------------|
| `api_version` | Number | _(Optional)_ The API version to use. For details, see [API Versioning](#api-versioning). |
| `api_version` | Number | _(Optional)_ The API version to use. If omitted, uses version `1`. For details, see [API Versioning](#api-versioning). |
| (Method Parameters) | (Various) | Provide any parameters to the method here. |
See [Response Formatting](response-formatting.md) for the response from the server.
@@ -91,7 +95,7 @@ Put the API method name after any normal (dash-prefaced) commandline options, fo
The commandline calls JSON-RPC, so its responses always match the JSON-RPC [response format](response-formatting.md).
The commandline always uses the latest [API version](./index.md#api-versioning).
The commandline always uses the latest [API version](#api-versioning).
{% admonition type="warning" name="Caution" %}The commandline interface is intended for administrative purposes only and is _not a supported API_. New versions of `rippled` may introduce breaking changes to the commandline API without warning!{% /admonition %}

View File

@@ -6,38 +6,37 @@ metadata:
---
# HTTP / WebSocket APIs
You can communicate directly with the XRP Ledger through HTTP-based APIs provided by the core `rippled` server as well as the Clio server. Both types of server provide JSON-RPC and WebSocket APIs with mostly the same functionality. JSON-RPC uses a strict request-response paradigm similar to a REST API, but WebSocket uses a single persistent connection where the server can push messages to the client asynchronously. For more information, see [Get Started Using HTTP / WebSocket APIs](../../tutorials/http-websocket-apis/build-apps/get-started.md).
[{% inline-svg file="/docs/img/api-functionality-venn-diagram.svg" /%}](/docs/img/api-functionality-venn-diagram.svg "Diagram: Most API methods are provided by both rippled and Clio servers. The rippled server provides admin methods, provides pending/unvalidated data including transaction queue, and has a live view of consensus and peer-to-peer network. The Clio server scales efficiently, provides additional methods nft_history, nft_info, nfts_by_issuer, and mpt_holders, and serves rippled-exclusive API requests by forwarding.")
## API Versioning
You can communicate with the XRP Ledger through the `rippled` servers' publicly available APIs.
Currently, there are two API versions: `1` and `2` {% badge href="https://github.com/XRPLF/rippled/releases/tag/2.0.0" %}New in: rippled 2.0.0{% /badge %}. The server reports the range of supported API versions in the [`version` API method](public-api-methods/server-info-methods/version.md); you can specify which version to use in your API requests.
- For a full list of the differences between API versions, see [API-CHANGELOG on GitHub](https://github.com/XRPLF/rippled/blob/develop/API-CHANGELOG.md).
- To stay up-to-date with API changes, join the [ripple server mailing list](https://groups.google.com/g/ripple-server).
### Specifying a Version
Use the `api_version` field of the request to specify which API version to use. See [Request Formatting](./api-conventions/request-formatting.md) for example requests.
Separate API requests can use different API versions even on the same persistent connection. For example, if you connect through WebSocket to a server that supports API versions 1 and 2, you can make an `account_tx` request using API version 2 and then make another `account_tx` request using API version 1 from the same connection.
### Default API Versions
- For a full list of the differences between API versions, see [API-CHANGELOG on GitHub](https://github.com/xrplf/rippled/blob/develop/API-CHANGELOG.md).
- To stay up-to-date with API changes, join the [ripple server mailing list](https://groups.google.com/g/ripple-server).
If you do not specify an API version when making a request directly to the server, the server uses API v1. However, some [client libraries](../client-libraries.md) automatically use a different API version if you do not specify one. The following table shows which API version each library uses when you don't specify which API version to use:
| Client Library | API Version | Additional Notes |
|-----------------------------------------------|-------------|------------------|
| None - direct WebSocket / JSON-RPC connection | 1 | |
| None - `rippled` Commandline | 2 | The commandline only uses the latest API version. |
| [xrpl.js](https://github.com/XRPLF/xrpl.js) | 2 | Versions 3.x and older use API v1 by default. |
| [xrpl-py](https://github.com/XRPLF/xrpl-py) | 2 | Versions 2.x and older use API v1 by default. |
## Default API Versions
The table below shows which version of the `rippled` API is used if you don't specify it in the request:
| Request Method | API Version | Additional Notes |
|----------------|-------------|------------------|
| Websocket | 1 | |
| JSON-RPC | 1 | |
| Commandline | 2 | The commandline only uses the latest API version. |
| [xrpl.js](https://github.com/XRPLF/xrpl.js) | 2 | Defaults to [API v2][] starting in v4.0.0. |
| [xrpl-py](https://github.com/XRPLF/xrpl-py) | 2 | Defaults to [API v2][] starting in v3.0.0. |
{% admonition type="info" name="Note" %}
Clio behaves the same as `rippled`.
{% /admonition %}
Future versions of `rippled` that introduce breaking changes will introduce a new API version 3.
### Breaking Changes
New API versions can introduce breaking changes. The following types of changes are **breaking changes**:
The following types of changes are **breaking changes**:
- Removing or renaming a field of a request or response.
- Changing the type of a field of a request or response.
@@ -45,10 +44,16 @@ New API versions can introduce breaking changes. The following types of changes
- Changing the order of positional parameters, or adding a new field before other positional parameters.
- Removing or renaming an API method.
- Changing the behavior of an API function visible to existing clients.
- The following types of breaking changes only apply to the gRPC API:
- Changing a `proto` field number.
- Removing or renaming an enum or enum value.
- Adding or removing fields from a `oneof`.
- Splitting or merging a `oneof`.
- Changing whether a message field is `optional`, `repeated`, or `required`.
- Changing the stream value of a request or response.
- Deleting or renaming a package or service.
Any time a full release introduces a breaking change, it introduces a new API version number.
API versions are subject to change until they are included in a stable release of the server. New API versions are expected to experience multiple breaking changes across development, beta, and pre-release software.
Any time a full release introduces a breaking change, it introduces a new API version number. Pre-release, beta, and development versions may introduce breaking changes to the same API version number.
### Non-Breaking Changes
@@ -56,11 +61,7 @@ The following types of changes are **non-breaking changes** and may occur withou
- Adding a new field to a request or response, not including positional parameters.
- Adding a new API method.
- Fixing a bug so that the API matches prior documentation and behavior.
## API Method References
{% child-pages /%}
{% raw-partial file="/docs/_snippets/common-links.md" /%}
{% child-pages /%}

View File

@@ -59,7 +59,29 @@ A request can include the following fields:
| `binary` | Boolean | No | If `true`, return ledger entries as hexadecimal strings instead of JSON. The default is `false`. |
| `limit` | Number | No | Limit the number of ledger entries to retrieve. The server may return fewer than this number of entries. Cannot be more than 2048 (when requesting binary) or 256 (when requesting JSON). Positive values outside this range are replaced with the closest valid option. The default is the maximum. |
| `marker` | [Marker][] | No | Value from a previous paginated response. Resume retrieving data where that response left off. |
| `type` | String | No | Filter results to a specific type of ledger entry. This field accepts canonical names of [ledger entry types](../../../protocol/ledger-data/ledger-entry-types/index.md) (case insensitive) or [short names](../../api-conventions/ledger-entry-short-names.md). If omitted, return ledger entries of all types. |
| `type` | String | No | Filter results to a specific type of ledger entry. This field accepts canonical ledger entry names (case insensitive) or short names. |
Valid `type` field values are:
| Canonical Name | Short Name |
| ----------------- | ----------------- |
| `AccountRoot` | `account` |
| `Amendments` | `amendments` |
| `AMM` | `amm` |
| `Check` | `check` |
| `DepositPreauth` | `deposit_preauth` |
| `DirectoryNode` | `directory` |
| `Escrow` | `escrow` |
| `FeeSettings` | `fee` |
| `LedgerHashes` | `hashes` |
| `MPToken` | `mptoken` |
| `MPTokenIssuance` | `mpt_issuance` |
| `NFTokenOffer ` | `nft_offer` |
| `Offer` | `offer` |
| `PayChannel` | `payment_channel` |
| `RippleState` | `state` |
| `SignerList` | `signer_list` |
| `Ticket` | `ticket` |
The `ledger` field is deprecated and may be removed without further notice.

View File

@@ -115,10 +115,4 @@ The ID of an AccountRoot entry is the [SHA-512Half][] of the following values, c
* The Account space key (`0x0061`)
* The AccountID of the account
## See Also
- **Transactions:**
- [AccountSet transaction][]
- [AccountDelete transaction][]
{% raw-partial file="/docs/_snippets/common-links.md" /%}

View File

@@ -119,15 +119,4 @@ The ID of an `AMM` entry is the [SHA-512Half][] of the following values, concate
For XRP, use all 0's for both the token and the issuer.
## See Also
- **Transactions:**
- [AMMBid transaction][]
- [AMMClawback transaction][]
- [AMMCreate transaction][]
- [AMMDelete transaction][]
- [AMMDeposit transaction][]
- [AMMVote transaction][]
- [AMMWithdraw transaction][]
{% raw-partial file="/docs/_snippets/common-links.md" /%}

View File

@@ -66,10 +66,4 @@ In addition to the [common fields](../common-fields.md), {% code-page-name /%} e
| `LockingChainDoor` | String | Account | Yes | The door account on the locking chain. |
| `LockingChainIssue` | Issue | Issue | Yes | The asset that is locked and unlocked on the locking chain. |
## See Also
- **Transactions:**
- [XChainCreateBridge transaction][]
- [XChainModifyBridge transaction][]
{% raw-partial file="/docs/_snippets/common-links.md" /%}

View File

@@ -75,11 +75,4 @@ The ID of a `Check` entry is the [SHA-512Half][] of the following values, concat
See the tutorial showing how to [Send a Check](../../../../tutorials/how-tos/use-specialized-payment-types/use-checks/send-a-check.md).
## See Also
- **Transactions:**
- [CheckCancel transaction][]
- [CheckCash transaction][]
- [CheckCreate transaction][]
{% raw-partial file="/docs/_snippets/common-links.md" /%}

View File

@@ -65,11 +65,4 @@ The unique ID of a Credential entry is the SHA-512Half hash of the following val
* The `Issuer` field's value; and
* The `CredentialType` field's value.
## See Also
- **Transactions:**
- [CredentialAccept transaction][]
- [CredentialCreate transaction][]
- [CredentialDelete transaction][]
{% raw-partial file="/docs/_snippets/common-links.md" /%}

View File

@@ -11,25 +11,6 @@ The `FeeSettings` entry contains the current base [transaction cost](../../../..
## Example {% $frontmatter.seo.title %} JSON
This ledger entry has two formats, depending on whether the [XRPFees amendment][] was enabled at the time:
{% tabs %}
{% tab label="Current Format" %}
```json
{
"BaseFeeDrops": "10",
"Flags": 0,
"LedgerEntryType": "FeeSettings",
"PreviousTxnID": "4EEDB01BB943CE32E97BB468AC179ABF933B272D6FF990E76B6721FB48E069FC",
"PreviousTxnLgrSeq": 92508417,
"ReserveBaseDrops": "1000000",
"ReserveIncrementDrops": "200000",
"index": "4BC50C9B0D8515D3EAAE1E74B29A95804346C491EE1A95BF25E4AAB854A6A651"
}
```
{% /tab %}
{% tab label="Legacy Format" %}
```json
{
"BaseFee": "000000000000000A",
@@ -41,28 +22,16 @@ This ledger entry has two formats, depending on whether the [XRPFees amendment][
"index": "4BC50C9B0D8515D3EAAE1E74B29A95804346C491EE1A95BF25E4AAB854A6A651"
}
```
{% /tab %}
{% /tabs %}
## {% $frontmatter.seo.title %} Fields
The fields of the `FeeSettings` ledger entry depend on whether the [XRPFees amendment][] was enabled the last time it was modified. If the last update was before the amendment became enabled, the entry uses the **legacy format**. If it has been updated after the amendment, it uses the **current format**. The fields it can have, in addition to the [common fields](../common-fields.md), are as follows:
In addition to the [common fields](../common-fields.md), the {% code-page-name /%} ledger entry has the following fields:
{% tabs %}
{% tab label="Current Format" %}
| Name | JSON Type | [Internal Type][] | Required? | Description |
|:------------------------|:----------|:------------------|:----------|:-----------------------|
| `BaseFeeDrops` | String | Amount | Yes | The [transaction cost](../../../../concepts/transactions/transaction-cost.md) of the "reference transaction" in drops of XRP. |
| `ReserveBaseDrops` | String | Amount | Yes | The [base reserve](../../../../concepts/accounts/reserves.md#base-reserve-and-owner-reserve) for an account in the XRP Ledger, as drops of XRP. |
| `ReserveIncrementDrops` | String | Amount | Yes | The incremental [owner reserve](../../../../concepts/accounts/reserves.md#base-reserve-and-owner-reserve) for owning objects, as drops of XRP. |
| `PreviousTxnID` | String | UInt256 | No | The identifying hash of the transaction that most recently modified this entry. _(Added by the [fixPreviousTxnID amendment][].)_ |
| `PreviousTxnLgrSeq` | Number | UInt32 | No | The [index of the ledger][Ledger Index] that contains the transaction that most recently modified this entry. _(Added by the [fixPreviousTxnID amendment][].)_ |
{% /tab %}
{% tab label="Legacy Format" %}
| Name | JSON Type | [Internal Type][] | Required? | Description |
|:--------------------|:----------|:------------------|:----------|:-----------------------|
| `BaseFee` | String | UInt64 | Yes | The [transaction cost](../../../../concepts/transactions/transaction-cost.md) of the "reference transaction" in drops of XRP as hexadecimal. |
| `Flags` | Number | UInt32 | Yes | A bit-map of boolean flags enabled for this object. Currently, the protocol defines no flags for `FeeSettings` objects. The value is always `0`. |
| `LedgerEntryType` | String | UInt16 | Yes | The value `0x0073`, mapped to the string `FeeSettings`, indicates that this object contains the ledger's fee settings. |
| `ReferenceFeeUnits` | Number | UInt32 | Yes | The `BaseFee` translated into "fee units". |
| `ReserveBase` | Number | UInt32 | Yes | The [base reserve](../../../../concepts/accounts/reserves.md#base-reserve-and-owner-reserve) for an account in the XRP Ledger, as drops of XRP. |
| `ReserveIncrement` | Number | UInt32 | Yes | The incremental [owner reserve](../../../../concepts/accounts/reserves.md#base-reserve-and-owner-reserve) for owning objects, as drops of XRP. |
@@ -71,8 +40,16 @@ The fields of the `FeeSettings` ledger entry depend on whether the [XRPFees amen
{% admonition type="danger" name="Warning" %}The JSON format for this ledger entry type is unusual. The `BaseFee`, `ReserveBase`, and `ReserveIncrement` indicate drops of XRP but ***not*** in the usual format for [specifying XRP][Currency Amount].{% /admonition %}
{% /tab %}
{% /tabs %}
If the _[XRPFees amendment][]_ is enabled, the `FeeSettings` object has these fields instead:
| Name | JSON Type | [Internal Type][] | Required? | Description |
|:------------------------|:----------|:------------------|:----------|:-----------------------|
| `BaseFeeDrops` | String | Amount | Yes | The [transaction cost](../../../../concepts/transactions/transaction-cost.md) of the "reference transaction" in drops of XRP. |
| `Flags` | Number | UInt32 | Yes | A bitmap of boolean flags enabled for this object. Currently, the protocol defines no flags for `FeeSettings` objects. The value is always `0`. |
| `LedgerEntryType` | String | UInt16 | Yes | The value `0x0073`, mapped to the string `FeeSettings`, indicates that this object contains the ledger's fee settings. |
| `ReserveBaseDrops` | String | Amount | Yes | The [base reserve](../../../../concepts/accounts/reserves.md#base-reserve-and-owner-reserve) for an account in the XRP Ledger, as drops of XRP. |
| `ReserveIncrementDrops` | String | Amount | Yes | The incremental [owner reserve](../../../../concepts/accounts/reserves.md#base-reserve-and-owner-reserve) for owning objects, as drops of XRP. |
## {% $frontmatter.seo.title %} Flags

View File

@@ -60,8 +60,4 @@ Besides errors that can occur for all transactions, {% $frontmatter.seo.title %}
| `tecHAS_OBLIGATIONS` | Occurs if the account to be deleted is connected to objects that cannot be deleted in the ledger. (This includes objects created by other accounts, such as [escrows](../../../../concepts/payment-types/escrow.md) and for example [NFT's minted](nftokenmint.md), [even if owned by another account](https://github.com/XRPLF/rippled/blob/master/src/xrpld/app/tx/detail/DeleteAccount.cpp#L197).) |
| `tefTOO_BIG` | Occurs if the sending account is linked to more than 1000 objects in the ledger. The transaction could succeed on retry if some of those objects were deleted separately first. |
## See Also
- [AccountRoot entry][]
{% raw-partial file="/docs/_snippets/common-links.md" /%}

View File

@@ -158,10 +158,6 @@ See [Transfer Fees](../../../../concepts/tokens/transfer-fees.md) for more infor
To remove an authorized minter, set `ClearFlag` to 10 (`asfAuthorizedNFTokenMinter`) and omit the `NFTokenMinter` field.
## See Also
- [AccountRoot entry][]
<!-- SPELLING_IGNORE: TransferRate -->
{% raw-partial file="/docs/_snippets/common-links.md" /%}

View File

@@ -142,8 +142,4 @@ Besides errors that can occur for all transactions, {% $frontmatter.seo.title %}
| `terNO_ACCOUNT` | One of the accounts specified in this request do not exist. |
| `terNO_AMM` | The Automated Market Maker instance for the asset pair in this transaction does not exist. |
## See Also
- [AMM entry][]
{% raw-partial file="/docs/_snippets/common-links.md" /%}

View File

@@ -66,8 +66,4 @@ Besides errors that can occur for all transactions, `AMMClawback` transactions c
| `temMALFORMED` | Occurs if the `issuer` subfield doesn't match between `Asset` and `Account`, `Account` is the same as the `Holder`, or `Asset` is XRP. |
| `terNO_AMM` | Occurs if the AMM pool specified by `Asset` and `Asset2` doesn't exist. |
## See Also
- [AMM entry][]
{% raw-partial file="/docs/_snippets/common-links.md" /%}

View File

@@ -69,8 +69,4 @@ Besides errors that can occur for all transactions, {% $frontmatter.seo.title %}
| `temBAD_FEE` | The `TradingFee` value is invalid. It must be zero or a positive integer and cannot be over 1000. |
| `temDISABLED` | The AMM feature is not enabled on this network. |
## See Also
- [AMM entry][]
{% raw-partial file="/docs/_snippets/common-links.md" /%}

View File

@@ -53,8 +53,4 @@ Besides errors that can occur for all transactions, AMMCreate transactions can r
| `tecINCOMPLETE` | There were too many associated ledger entries to fully delete, so the transaction removed as many as it could, but the AMM has not been fully deleted. You can send another AMMDelete transaction to continue and possibly finish the job. |
| `terNO_AMM` | The specified AMM does not exist. (It may have been deleted already, or you may have specified a wrong asset for the AMM you intended.) |
## See Also
- [AMM entry][]
{% raw-partial file="/docs/_snippets/common-links.md" /%}

View File

@@ -147,8 +147,4 @@ Besides errors that can occur for all transactions, {% $frontmatter.seo.title %}
| `terNO_ACCOUNT` | An account specified in the request does not exist. |
| `terNO_AMM` | The Automated Market Maker instance for the asset pair in this transaction does not exist. |
## See Also
- [AMM entry][]
{% raw-partial file="/docs/_snippets/common-links.md" /%}

View File

@@ -55,8 +55,4 @@ Besides errors that can occur for all transactions, {% $frontmatter.seo.title %}
| `temBAD_FEE` | The `TradingFee` from this transaction is not valid. |
| `terNO_AMM` | The Automated Market Maker instance for the asset pair in this transaction does not exist. |
## See Also
- [AMM entry][]
{% raw-partial file="/docs/_snippets/common-links.md" /%}

View File

@@ -123,8 +123,4 @@ Besides errors that can occur for all transactions, {% $frontmatter.seo.title %}
| `temBAD_AMM_TOKENS` | The transaction specified the LP Tokens incorrectly; for example, the `issuer` is not the AMM's associated AccountRoot address or the `currency` is not the currency code for this AMM's LP Tokens, or the transaction specified this AMM's LP Tokens in one of the asset fields. |
| `terNO_AMM` | The Automated Market Maker instance for the asset pair in this transaction does not exist. |
## See Also
- [AMM entry][]
{% raw-partial file="/docs/_snippets/common-links.md" /%}

View File

@@ -38,8 +38,4 @@ _(Added by the [Checks amendment][].)_
- If the object identified by the `CheckID` does not exist or is not a Check, the transaction fails with the result `tecNO_ENTRY`.
- If the Check is not expired and the sender of the CheckCancel transaction is not the source or destination of the Check, the transaction fails with the result `tecNO_PERMISSION`.
## See Also
- [Check entry][]
{% raw-partial file="/docs/_snippets/common-links.md" /%}

View File

@@ -49,8 +49,4 @@ The transaction ***must*** include either `Amount` or `DeliverMin`, but not both
- If the transaction specifies both `Amount` and `DeliverMin`, or omits both, the transaction fails with the result `temMALFORMED`.
- If the `Amount` or `DeliverMin` does not match the currency (and issuer, if not XRP) of the Check, the transaction fails with the result `temBAD_CURRENCY`.
## See Also
- [Check entry][]
{% raw-partial file="/docs/_snippets/common-links.md" /%}

View File

@@ -51,8 +51,4 @@ _(Added by the [Checks amendment][].)_
- If the sender does not have enough XRP to meet the [owner reserve](../../../../concepts/accounts/reserves.md#owner-reserves) after adding the Check, the transaction fails with the result `tecINSUFFICIENT_RESERVE`.
- If either the sender or the destination of the Check cannot own more objects in the ledger, the transaction fails with the result `tecDIR_FULL`.
## See Also
- [Check entry][]
{% raw-partial file="/docs/_snippets/common-links.md" /%}

View File

@@ -48,8 +48,5 @@ The combination of `Account`, `Issuer`, and `CredentialType` must match a `Crede
| `temINVALID_ACCOUNT_ID` | The provided `Issuer` field is invalid. For example, it contains [ACCOUNT_ZERO](../../../../concepts/accounts/addresses.md#special-addresses). |
| `temINVALID_FLAG` | The transaction includes a [Flag](../common-fields.md#flags-field) that does not exist, or includes a contradictory combination of flags. _(Requires the [fixInvalidTxFlags amendment][] {% not-enabled /%})_ |
## See Also
- [Credential entry][]
{% raw-partial file="/docs/_snippets/common-links.md" /%}

View File

@@ -50,8 +50,5 @@ Besides errors that can occur for all transactions, CredentialCreate transaction
| `temINVALID_ACCOUNT_ID` | The provided `Subject` field is invalid. For example, it contains [ACCOUNT_ZERO](../../../../concepts/accounts/addresses.md#special-addresses). |
| `temINVALID_FLAG` | The transaction includes a [Flag](../common-fields.md#flags-field) that does not exist, or includes a contradictory combination of flags. _(Requires the [fixInvalidTxFlags amendment][] {% not-enabled /%})_ |
## See Also
- [Credential entry][]
{% raw-partial file="/docs/_snippets/common-links.md" /%}

View File

@@ -49,8 +49,5 @@ This transaction looks for a [Credential ledger entry](../../ledger-data/ledger-
| `tecNO_ENTRY` | The specified credential does not exist in the ledger. |
| `temINVALID_FLAG` | The transaction includes a [Flag](../common-fields.md#flags-field) that does not exist, or includes a contradictory combination of flags. _(Requires the [fixInvalidTxFlags amendment][] {% not-enabled /%})_ |
## See Also
- [Credential entry][]
{% raw-partial file="/docs/_snippets/common-links.md" /%}

View File

@@ -61,8 +61,4 @@ The complete production-grade setup would also include a `SignerListSet` transac
| `LockingChainDoor` | String | AccountID | Yes | The door account on the locking chain. |
| `LockingChainIssue` | Issue | Issue | Yes | The asset that is locked and unlocked on the locking chain. |
## See Also
- [Bridge entry][]
{% raw-partial file="/docs/_snippets/common-links.md" /%}

View File

@@ -69,8 +69,4 @@ In addition to the universal transaction flags that are applicable to all transa
|------------------------------|--------------|-------------|
| `tfClearAccountCreateAmount` | `0x00010000` | Clears the `MinAccountCreateAmount` of the bridge. |
## See Also
- [Bridge entry][]
{% raw-partial file="/docs/_snippets/common-links.md" /%}

View File

@@ -1,3 +1,6 @@
/resources/contribute-documentation/tutorial-structure/:
to: /resources/contribute-documentation/tutorial-template/
type: 301
/docs/infrastructure/installation/rippled-1-3-migration-instructions/:
to: /docs/infrastructure/installation/
type: 301

View File

@@ -1,84 +1,138 @@
---
html: tutorial-guidelines.html
parent: contribute-documentation.html
seo:
description: Learn how this site's tutorials are structured and guidelines for contributing quality tutorials.
---
# Tutorial Guidelines
We are creating a modular tutorial framework that allows developers to learn how transactions and requests work on the XRP Ledger. Developers can review the modules to learn about business solutions, and potentially repurpose the scripts in their own applications.
We are creating a repository of tutorials and functional code samples that show how various features of the XRP Ledger work. Developers and large language models (LLMs) can use these tutorials and their associated code samples to learn about business solutions, and copy or adapt the scripts for use in their own applications.
The guidelines on this page don't need to be strictly enforced. It's OK to diverge from them in cases where you have good reason to.
# Rationale
## Rationale
What a developer wants comes down to two things:
The main purpose of tutorials is to provide **sample code** alongside natural-language text to further explain what the code does. This serves multiple purposes:
1. Sample code snippets they can copy and paste into their own applications.
2. Complete API reference documentation.
- Developers can copy and paste the sample code into their own applications.
- Large language models (LLMs) can use this as training data to generate high-quality code for use with the XRP Ledger.
Keep the conceptual information to a minimum only the information necessary to complete the tutorial. For background or deeper understanding, provide links to the conceptual topics at the end of the tutorial, if needed.
Conceptual information is sometimes necessary, but tutorials are not the place to discuss concepts at length. A tutorial should include a few sentences throughout to help provide context for the action occurring in the code, and should link out to concept and reference pages to provide background reading.
Modular tutorials follow Malcolm Knowles six assumptions for designing adult learning:
LLMs are increasingly being used in software development. To assist users of these tools, we would like to provide many working code samples that demonstrate best practices and follow consistent structure and style. Tutorials that have descriptions of what the code does alongside matching code snippets help LLMs develop the correct associations between terms used in natural language and programming language, hopefully leading to more accurate results from code generation.
1. Adults need to know why they need to learn something.
2. Adults need to build on their experience.
3. Adults have a need to feel responsible for their learning.
4. Adults are ready to learn if training solves an immediate problem.
5. Adults want their training to be problem focused.
6. Adults learn best when motivation comes intrinsically.
## Recommended Tutorial Structure
Add into that Ralph Smedleys quote, “We learn best in moments of enjoyment.” Taking a lighter touch helps to relax the learner so that the material flows into their brain with less resistance.
See [Tutorial Template](./tutorial-template.md) for the typical headers and contents expected for a new tutorial.
## Sample Code Guidelines
# Sample Code vs. Tasks vs. Concepts vs. Tutorials
Sample code is well commented scripts, snippets, or applications that illustrate common usage patterns and best practices. Advanced users can typically scan the example and use it immediately without a formal tutorial. Not every piece of sample code needs to be associated with a tutorial, but most tutorials will have a piece of sample code that serves as the basis for that tutorial.
To date, there have been some blurred lines where different types of documentation show up as _Tutorials_. Here are some comparisons that help define the distinction.
The XRPL.org maintainers are generally committed to providing sample code in both **JavaScript** and **Python** using the official client libraries for those languages. The site may occasionally provide more, depending on what the community needs and provides. This site is open-source, so if you want to maintain examples in other languages, feel free to volunteer!
However, due to the security concerns of using third party libraries, it may take a while to accept contributions in other programming languages.
## Sample Code
### Folder Layout
Sample code is well commented snippets or applications that illustrate best practices for implementing a feature of the API. Sample code is modular and reusable with little customization required.
Sample code should be provided in the `_code-samples/` folder at the top of this website's source repository, with separate subfolders by programming language. There should be a `README.md` file for each code sample _above_ the language folders describing what the code sample does in general, _and_ a `README.md` in each programming language folder describing how to install and run that code sample specifically.
Sample code is desirable, because advanced users can typically scan the example and use it immediately without a formal tutorial. It can also be used by others as a basis for tutorials. Sample code developers can focus on what they do well, while technical writers and support personnel can use the samples to create quality training materials.
For example:
```
- _code_samples/issue-credentials/
- js/
- README.md
- issue-credential.js
- package.json
- py/
- README.md
- issue_credential.py
- requirements.txt
- README.md
```
## Tasks
This information is used to populate the [Code Samples](/resources/code-samples/) page. The outer readme's header is the title of the code sample on that page, and the first paragraph is the description.
Tasks are step-by-step instructions for how to accomplish a specific result. For example, “Installing rippled on a Red Hat Linux Server.” Task documentation is not intended to be particularly educational. It frequently describes tasks that are only performed one time per implementation, or maintenance tasks that always follow a familiar pattern. Tasks provide troubleshooting guidance, since there are likely variables that the user must adjust based on the specifics of their use case.
### Comments
Comments are an important part of readable, accurate code, but don't go overboard. The text of a tutorial may be translated into other languages such as Japanese, while the sample code is kept the same, so don't include any critical information _only_ in the comments.
## Concepts
Use comments to separate out logical sections of the sample code. You can these comments as markers so that the `{% code-snippet ... %}` Markdoc component shows only the relevant section at a time in a tutorial.
Conceptual information describes elements of the API, how they work, and when to use them. If a tutorial requires lengthy explanations before or during the programming tasks, consider how you might separate the exposition into a new topic, or link to existing topics that set the proper context.
### Sample Code Types
For example, three paragraphs of context and a single line of code would be a concept, not a tutorial.
Sample code can take many forms, such as the following:
- **Sample Application** - A fully functional program that accepts user input to perform tasks with some flexibility. It may have a graphical user interface or only a commandline interface. Complete sample code for different stages of application development may be provided, but is not recommended because it's more work than it's worth.
- **Script** - A simple program that performs a predetermined set of tasks, often using hard-coded values, with minimal branching. These scripts are not expected to perform robust error handling; they typically exit when an error occurs.
- **Snippet** - A self-contained function or piece of code that demonstrates the best practices for doing one thing, but is not a complete program. Snippets are most likely to _not_ have an associated tutorial.
## Tutorials
All three types of sample code have their time and place. However, for most of this website's tutorials, _scripts_ are preferred for the following reasons:
Tutorials begin with sample code that illustrates best practices for implementing a feature. They take the developer step-by-step through the development process, explaining the purpose of each block of code.
- They demonstrate the relevant, XRPL-specific functionality with minimal distractions.
- You can run a script to demonstrate that it works and is accurate.
- Scripts are easier to create and have a lesser maintenance burden than more complex apps.
Tutorials further combine a number of features to work together to solve a business problem. They describe the straightforward sunny day path to complete a task. Then, the tutorial might suggest modifications that let the developer try several different scenarios. Due to their focus on a certain limited scope of behavior, tutorials should not require extensive troubleshooting information.
### JSON-RPC / WebSocket / Commandline Examples as Sample Code
Some legacy tutorials show example requests and responses using WebSocket, JSON-RPC APIs, or the `rippled` commandline. These are not recommended, for the following reasons:
## Use Cases
- People (or LLMs) who copy these formats tend to end up submitting their secret keys to public servers, which is extremely insecure.
- Many tutorials involve steps where you need application logic that can't be represented in API requests/responses. You end up with code in other programming languages anyway, or pseudocode, or just steps that are missing examples of how to do critical work.
- The API references already provide examples in these formats.
Use cases describe how to pull together multiple features to create a practical application that solves a business problem. They provide context and assistance with the decision making process, then provide links to the appropriate topics for each step of implementation.
If you do have good reason to provide commandline, WebSocket, or JSON-RPC examples, show both the request and an example response in separate code blocks.
### Dependencies
# Tutorial Components
Dependencies can be a source of maintenance burden, because you need to stay up-to-date with security fixes and breaking changes to the dependencies. On the other hand, reimplementing common utilities in every code sample is its own maintenance burden, and it's even worse to "roll your own" security-sensitive code. Some users may be working on codebases that are locked into competing/incompatible dependencies, which can make it harder to adapt your code to their situation; the more dependencies you have, the more likely this is to occur.
This section describes the elements of the modular tutorials used on XRPL.org.
Some guidelines:
1. Prefer standard library functions to third-party libraries, even if they're not quite as convenient to use.
- Use third-party libraries when they're _significantly_ more convenient than the standard library. For example, [even Python's official documentation recommends using the Requests lib instead of `urllib.request`](https://docs.python.org/3/library/urllib.request.html#module-urllib.request).
- When updating old code samples, look for cases where dependencies can be eliminated because the standard library has grown to encompass functionality that previously needed a library.
2. Implement your own functions when they're small and not security-sensitive; use libraries for complex or security-sensitive functions.
3. Prefer widely-used, actively maintained libraries.
## Sample Application
### General Guidelines and Best Practices
XRPL tutorial code samples are modular in nature. For example, Script 1 demonstrates how to create a test account, access the XRP Ledger, and transfer XRP between accounts. Any further samples can reuse the functions in Script 1.
The following guidelines apply for XRP Ledger code samples regardless of language:
Create a new script with the specific, minimal function code required to demonstrate the practical solution to a business problem. The examples should be incremental, with just enough behaviors to illustrate a business process.
- Don't hardcode secret keys, even example keys that don't hold real money. Instead, do any of the following:
- Fund a new account using the faucet.
- Prompt the user to paste the seed of the account they want to use.
- Read the secret key from an environment variable.
- Use `client` as the name for the API client instance.
- Print output to the console, especially before doing any network operations such as calling API methods or submitting transactions.
- Use the client library's "submit and wait" function when sending transactions. Autofill, sign, and submit the transaction all in one call.
- Use tabs for code samples even if you only have a code sample in one language.
- When making WebSocket/JSON-RPC API calls, use the latest API version and the `validated` ledger.
For example, the first NFT tutorial shows how to mint, retrieve, and burn an NFT. The next tutorial shows how to create and accept a sell offer, and create and accept a buy offer.
### Language-specific Guidelines
Dont focus too much on the UX of the application, unless the look and feel is pertinent to the topic. Use the standard CSS file with the look and feel for all of the tutorials.
{% tabs %}
Reuse the code from other modules when possible. There might be situations where you need to modify the behavior from an earlier module. You can either overload the function name or modify the module and save it with a different name.
{% tab label="JavaScript" %}
JavaScript code samples should:
- Use xrpl.js as the XRPL client library.
- Provide a `package.json` file that specifies `"type": "module"` and any relevant dependencies.
- Use **ES Module** syntax such as `import { Client } from "xrpl"`, not Common JS syntax such as `require("xrpl")`.
- Use `await` instead of `.done(...)` or `.then(...)`
- Follow [**JavaScript Standard Style**](https://standardjs.com).
- Be compatible with Node.js versions that are currently in maintenance (security) support.
- Preferably, be compatible with most widely-used web browsers too.
- When writing JSON objects to the console, use `JSON.stringify(example_object, null, 2)` so that Node.js doesn't skip the interesting inner parts of the object.
{% /tab %}
{% tab label="Python" %}
Python code samples should:
- Use xrpl-py as the XRPL client library
- Provide a `requirements.txt` file with relevant dependencies.
- Use the `JsonRpcClient` unless asynchronous functionality is needed.
- Follow [**Black Style**](https://black.readthedocs.io/en/stable/).
- Be compatible with Python versions that are currently in maintenance (security) support.
{% /tab %}
{% /tabs %}

View File

@@ -1,55 +0,0 @@
---
html: tutorial-structure.html
parent: contribute-documentation.html
seo:
description: A summary of the parts of a standard tutorial.
---
# Tutorial Structure
Each XRP Ledger tutorial follows the same format.
1. A brief description of the features illustrated in the tutorial.
2. Prerequisites for running the code, if needed, or links to the sample code.
3. Usage examples of the features in the tutorial.
4. A code walkthrough of the sample application, highlighting unique elements in the scripts.
5. See Also, with links to conceptual information or good tutorials to try as a next step.
Separate setup (prerequisites) from usage from code development. These are each different activities that engage different areas of the brain. Trying to think of all three elements at once leads to confusion and headaches.
## Description
![Description](/docs/img/tut-struct1.png)
List what the sample demonstrates. If possible, each example should describe the steps to accomplish specific related tasks. (For example, create a NFT Sell Offer, Accept a Sell Offer, Delete a Sell Offer.) There should be enough conceptual information to understand what the tutorial illustrates, with links to additional conceptual information, if needed.
## Prerequisites
![Prerequisites](/docs/img/tut-struct2.png)
Provide links to any required software and to all of the example code needed to run the tutorial. If necessary, give simple instructions for using third-party tools, but provide a link to the source website for the customer to do a deeper dive at their leisure.
## Usage Example
![Usage](/docs/img/tut-struct3.png)
Start by providing a finished, working example of the tutorial application. This is an opportunity for immediate success working with the software to solve a problem.
Use screenshots for each step of the tutorial these allow the user to understand the tutorial without having to run the code themselves. Of course we _want_ them to run the code, but this gives them a choice.
Describe the sunny day scenario. The application should run without problems if there is an uninterrupted connection to the internet. Dont provide a lot of troubleshooting information, unless its pertinent to the tutorial.
## Code Walkthrough
![Code Walkthrough](/docs/img/tut-struct4.png)
Walk through the code, one chunk at a time. Dont belabor topics that have been discussed in earlier examples. Provide sample code, but dont provide exhaustive explanations for how to program underlying platforms like HTML syntax unless there is something unique to the implementation.
An important thing to emphasize is that every interaction with the XRPL is either a transaction or a request, and that all transactions and requests are essentially the same. The sample code we provide shows how to prepare the transaction or request, and how to process the returned results. Knowing how to submit and respond to one transaction or request gives a pretty good idea for how to submit and respond to any transaction or request.
(Technically there is third category, similar to a request: a notification from a subscription stream. See [Subscription Methods](../../docs/references/http-websocket-apis/public-api-methods/subscription-methods/index.md).)
## See Also
![See Also](/docs/img/tut-struct5.png)
At the end of the tutorial, provide links to additional resources, conceptual information, and any tutorials that would be a sensible next step in the learning journey.

View File

@@ -0,0 +1,163 @@
---
seo:
description: A summary of the parts of a standard tutorial.
---
# Tutorial Template
This tutorial demonstrates the structure of a **[tutorial](./tutorial-guidelines.md)** in the XRPL.org standard style, including:
- Typical headings for a tutorial page
- Recommendations for code samples and usage
- Options and variations
The template should begin with an intro that states what the tutorial is about. The intro should have one or more "backlinks" to the conceptual documentation for the core concepts/features that the tutorial demonstrates. You may also want to add a small amount of additional context of _why_ or _when_ you would want to do whatever this tutorial does. Don't go overboard—leave the details for concept or use case articles.
## Goals
This section defines the learning goals of the tutorial:
- Bullet points are a succinct way of outlining learning steps.
- If the tutorial includes a graphical interface, include a screenshot of the final product here.
## Prerequisites
Prerequisites can take several forms:
- Knowledge and learning background, especially tutorials that this one builds on top of.
- Dev environment setup, especially basic depedencies such as your xrpl client library.
- Do not include dependencies that are specific to this tutorial here, because people tend to skim/gloss over this section. For dependencies specific to this tutorial, include them in the steps later.
- Specific on-chain structures that need to be in place in advance. For example, to trade against an AMM, the AMM must exist in the ledger.
- Amendments that need to be enabled for this tutorial. Use an amendment disclaimer component to show the Mainnet status of the amendment.
## Source Code
You can find the complete source code for this tutorial's examples in the {% repo-link path="resources/contribute-documentation/tutorial-structure.md" %}resources section of this website's repository{% /repo-link %}.
{% admonition type="success" name="Tip" %}
Use the `{% repo-link ... %}` component to link to the source files; this component is designed to adjust based on the environment, so for example previews link to the code on the preview branch... although it doesn't fully work as of this writing (2025-08-11).
{% /admonition %}
## Usage
To test that the code runs properly, you can navigate to the repository top and start the local Redocly server as follows:
```sh
npm run start
```
Then, navigate to <http://localhost:4000/resources/contribute-documentation/tutorial-structure> to view the parsed version of this page.
{% admonition type="info" name="Usage is optional" %}
You should include a Usage section in **sample app tutorials**. Provide a "Usage" section if this tutorial's sample code:
- Has a GUI with multiple buttons/inputs
- Is a commandline utility with multiple options/parameters
- Consists of multiple scripts that need to be run in a specific order
If there's a user interface, you can also embed a video demonstrating usage of the sample app.
For single-file scripts that perform a linear set of steps without user input, omit the Usage section.
{% /admonition %}
## Steps
Follow these steps to build a tutorial. Number the steps, because they help to orient readers to the structure and serve to identify the core part of the tutorial.
If you change the number or order of steps, remember to update the step numbers and update any links or mentions of specific steps, too.
### 11. Install dependencies
Unlike the ones in Prerequisites, this step is for dependencies that are specific to this tutorial. They're here because people tend to gloss over the preamble parts and skip straight to the "meat" of the tutorial.
{% tabs %}
{% tab label="JavaScript" %}
From the code sample folder, use npm to install dependencies:
```sh
npm i
```
{% /tab %}
{% tab label="Python" %}
From the code sample folder, use pip to install dependencies:
```sh
pip install -r requirements.txt
```
{% /tab %}
{% /tabs %}
### 2. Connect and get account(s)
Each step should have a heading in the imperative, in sentence case. Beneath the heading should be a sentence or two introducing the action being taken at this stage of the code sample in more detail. The code samples should be in tabs per programming language.
Most code samples need at least one account. The first step should generally cover from the start of the file (including imports) through instantiating a client, connecting to a network, and deriving wallets and/or funding accounts via the faucet.
{% tabs %}
{% tab label="JavaScript" %}
{% code-snippet file="/_code-samples/verify-credential/js/verify_credential.js" language="js" before="// Look up Credential" /%}
{% /tab %}
{% /tabs %}
{% admonition type="info" name="Code snippets and steps" %}
Each "step" of the tutorial should correspond to one code snippet (with tabs by programming language). There can be exceptions, for example if one programming language needs additional code in a separate place to make the same functionality work.
{% /admonition %}
### 3. Check for on-ledger structures
If a script depends on certain ledger data already existing (for example, you are supposed to create it with a different script), the script should have an explicit step to check for the existence of that data. You should also mention the requirement in the [**Prerequisites**](#prerequisites) section.
{% tabs %}
{% tab label="JavaScript" %}
{% code-snippet file="/_code-samples/verify-credential/js/verify_credential.js" language="js" from="// Look up Credential" before="// Check if the credential has been accepted" /%}
{% /tab %}
{% /tabs %}
### 4. Add next step
Each additional step should directly continue the code sample from the previous step without skipping anything, to the extent possible.
{% tabs %}
{% tab label="JavaScript" %}
{% code-snippet file="/_code-samples/verify-credential/js/verify_credential.js" language="js" from="// Check if the credential has been accepted" before="// Confirm that the credential is not expired" /%}
{% /tab %}
{% /tabs %}
Optionally, you can provide additional text after the code snippet, such as an explanation of the expected output from this step, or details that you should note down for later.
### 5. Use as many steps as necessary
If the code snippet calls an API method, link to the relevant reference documentation. If you include the common links file, you can generally do this with an automatic link such as the `[ledger method][]`, which turns into the [ledger method][].
{% tabs %}
{% tab label="JavaScript" %}
{% code-snippet file="/_code-samples/verify-credential/js/verify_credential.js" language="js" from="// Confirm that the credential is not expired" before="// Credential has passed all checks" /%}
{% /tab %}
{% /tabs %}
{% admonition type="success" name="The right number of steps" %}
Most tutorials should have 3-7 steps. If the tutorial has fewer, maybe it doesn't need to be a tutorial, or maybe you should go into more detail. If it has more, consider splitting it into multiple tutorials.
{% /admonition %}
### 6. Final step
Use `{% code-snippet ... %}` tags instead of copy-paste to display the code samples, so that you don't have to manually keep the code in the doc synchronized with changes to the code sample. To facilitate this, use `from=` and `before=` strings based on unique comments in the code. The first code snippet should omit `from=` and the last should omit `before=`.
{% tabs %}
{% tab label="JavaScript" %}
{% code-snippet file="/_code-samples/verify-credential/js/verify_credential.js" language="js" from="// Credential has passed all checks" /%}
{% /tab %}
{% /tabs %}
## See Also
At the end of the tutorial, provide links to additional resources that would be a sensible next step in the learning journey. This could be more tutorials, use cases, or other pages. It's also a good idea to add links here to reference documentation for any API methods, transaction types, and ledger entries used in the tutorial—even though those links should be redundant with links scattered throughout the text of the tutorial.
{% raw-partial file="/docs/_snippets/common-links.md" /%}

View File

@@ -181,102 +181,148 @@
expanded: false
items:
- page: docs/tutorials/public-servers.md
- label: Get Started
- page: docs/tutorials/javascript/index.md
expanded: false
items:
- page: docs/tutorials/get-started/get-started-javascript.md
- page: docs/tutorials/get-started/get-started-python.md
- page: docs/tutorials/get-started/get-started-java.md
- page: docs/tutorials/get-started/get-started-php.md
- page: docs/tutorials/get-started/get-started-http-websocket-apis.md
- label: Sample Apps
expanded: false
items:
- page: docs/tutorials/sample-apps/build-a-browser-wallet-in-javascript.md
- page: docs/tutorials/sample-apps/build-a-desktop-wallet-in-javascript.md
- page: docs/tutorials/sample-apps/build-a-desktop-wallet-in-python.md
- page: docs/tutorials/sample-apps/credential-issuing-service-in-javascript.md
- page: docs/tutorials/sample-apps/credential-issuing-service-in-python.md
- label: Payments
expanded: false
items:
- page: docs/tutorials/javascript/send-payments/create-accounts-send-xrp.md
- page: docs/tutorials/javascript/send-payments/create-trust-line-send-currency.md
- label: DEX
expanded: false
items:
- page: docs/tutorials/dex/trade-in-the-decentralized-exchange.md
- page: docs/tutorials/dex/create-an-automated-market-maker.md
- page: docs/tutorials/dex/create-an-amm-in-javascript.md
- page: docs/tutorials/dex/add-assets-to-amm-in-javascript.md
- page: docs/tutorials/dex/trade-with-auction-slot-in-javascript.md
- page: docs/tutorials/javascript/send-payments/create-offers.md
- label: Tokens
expanded: false
items:
- label: NFTs
- page: docs/tutorials/javascript/amm/index.md
expanded: false
items:
- page: docs/tutorials/javascript/amm/create-an-amm.md
- page: docs/tutorials/javascript/amm/add-assets-to-amm.md
- page: docs/tutorials/javascript/amm/trade-with-auction-slot.md
- page: docs/tutorials/javascript/send-payments/index.md
expanded: false
items:
- page: docs/tutorials/javascript/send-payments/create-accounts-send-xrp.md
- page: docs/tutorials/javascript/send-payments/create-trust-line-send-currency.md
- page: docs/tutorials/javascript/send-payments/create-offers.md
- page: docs/tutorials/javascript/send-payments/create-time-based-escrows.md
- page: docs/tutorials/javascript/send-payments/create-conditional-escrows.md
- page: docs/tutorials/javascript/send-payments/send-and-cash-checks.md
- page: docs/tutorials/javascript/send-payments/sending-mpts.md
- page: docs/tutorials/javascript/nfts/index.md
expanded: false
items:
- page: docs/tutorials/javascript/nfts/mint-and-burn-nfts.md
- page: docs/tutorials/javascript/nfts/transfer-nfts.md
- page: docs/tutorials/javascript/nfts/broker-an-nft-sale.md
- page: docs/tutorials/javascript/nfts/assign-an-authorized-minter.md
- page: docs/tutorials/javascript/nfts/batch-mint-nfts.md
- label: Fungible Tokens
- page: docs/tutorials/javascript/nfts/batch-mint-nfts.md
- page: docs/tutorials/javascript/build-apps/index.md
expanded: false
items:
- page: docs/tutorials/javascript/tokens/issue-a-fungible-token.md
- page: docs/tutorials/how-tos/use-tokens/freeze-a-trust-line.md
- page: docs/tutorials/how-tos/use-tokens/enact-global-freeze.md
- page: docs/tutorials/how-tos/use-tokens/enable-no-freeze.md
- label: Multi-Purpose Tokens (Tokens 2.0)
- page: docs/tutorials/javascript/build-apps/get-started.md
- page: docs/tutorials/javascript/build-apps/build-a-browser-wallet-in-javascript.md
- page: docs/tutorials/javascript/build-apps/build-a-desktop-wallet-in-javascript.md
- page: docs/tutorials/javascript/build-apps/credential-issuing-service.md
- page: docs/tutorials/javascript/compliance/index.md
items:
- page: docs/tutorials/javascript/compliance/create-permissioned-domains.md
- page: docs/tutorials/javascript/compliance/verify-credential.md
- page: docs/tutorials/python/index.md
expanded: false
items:
- page: docs/tutorials/python/send-payments/index.md
expanded: false
items:
- page: docs/tutorials/javascript/multi-purpose-tokens/issue-a-multi-purpose-token.md
- page: docs/tutorials/javascript/send-payments/sending-mpts.md
- label: Compliance Features
- page: docs/tutorials/python/send-payments/create-accounts-send-xrp.md
- page: docs/tutorials/python/send-payments/create-trust-line-send-currency.md
- page: docs/tutorials/python/send-payments/create-time-based-escrows.md
- page: docs/tutorials/python/send-payments/create-conditional-escrows.md
- page: docs/tutorials/python/send-payments/send-and-cash-checks.md
- page: docs/tutorials/python/nfts/index.md
expanded: false
items:
- page: docs/tutorials/python/nfts/mint-and-burn-nfts.md
- page: docs/tutorials/python/nfts/transfer-nfts.md
- page: docs/tutorials/python/nfts/broker-an-nft-sale.md
- page: docs/tutorials/python/nfts/assign-an-authorized-minter.md
- page: docs/tutorials/python/nfts/batch-mint-nfts.md
- page: docs/tutorials/python/build-apps/index.md
expanded: false
items:
- page: docs/tutorials/python/build-apps/get-started.md
- page: docs/tutorials/python/build-apps/build-a-desktop-wallet-in-python.md
- page: docs/tutorials/python/build-apps/credential-issuing-service.md
- page: docs/tutorials/python/compliance/index.md
items:
- page: docs/tutorials/python/compliance/verify-credential.md
- page: docs/tutorials/java/index.md
expanded: false
items:
- page: docs/tutorials/javascript/compliance/create-permissioned-domains.md
- page: docs/tutorials/javascript/compliance/verify-credential.md
- label: Programmability
- page: docs/tutorials/java/build-apps/index.md
expanded: false
items:
- page: docs/tutorials/java/build-apps/get-started.md
- page: docs/tutorials/php/index.md
expanded: false
items:
- page: docs/tutorials/how-tos/use-xrpl-sidechains/set-up-xrp-xrp-bridge.md
- page: docs/tutorials/how-tos/use-xrpl-sidechains/set-up-iou-iou-bridge.md
- page: docs/tutorials/how-tos/use-xrpl-sidechains/submit-cross-chain-transaction.md
- label: Best Practices
- page: docs/tutorials/php/build-apps/index.md
expanded: false
items:
- page: docs/tutorials/php/build-apps/get-started.md
- page: docs/tutorials/http-websocket-apis/index.md
expanded: false
items:
- label: API Usage
- page: docs/tutorials/http-websocket-apis/build-apps/index.md
expanded: false
items:
- page: docs/tutorials/javascript/compliance/create-permissioned-domains.md
- label: Transaction Sending
items:
- page: docs/tutorials/http-websocket-apis/build-apps/get-started.md
- page: docs/tutorials/http-websocket-apis/build-apps/monitor-incoming-payments-with-websocket.md
- page: docs/tutorials/how-tos/index.md
expanded: false
items:
- page: docs/tutorials/how-tos/send-xrp.md
- page: docs/tutorials/how-tos/manage-account-settings/index.md
expanded: false
items:
- page: docs/tutorials/how-tos/manage-account-settings/use-tickets.md
- label: Key Management
expanded: false
items:
- page: docs/tutorials/how-tos/manage-account-settings/set-up-multi-signing.md
- page: docs/tutorials/how-tos/manage-account-settings/send-a-multi-signed-transaction.md
items:
- page: docs/tutorials/how-tos/manage-account-settings/assign-a-regular-key-pair.md
- page: docs/tutorials/how-tos/manage-account-settings/change-or-remove-a-regular-key-pair.md
- page: docs/tutorials/how-tos/manage-account-settings/disable-master-key-pair.md
- page: docs/tutorials/how-tos/manage-account-settings/offline-account-setup.md
- label: Advanced Developer Topics
expanded: false
items:
- label: Client Library Development
- page: docs/tutorials/how-tos/manage-account-settings/disable-master-key-pair.md
- page: docs/tutorials/how-tos/manage-account-settings/set-up-multi-signing.md
- page: docs/tutorials/how-tos/manage-account-settings/send-a-multi-signed-transaction.md
- page: docs/tutorials/how-tos/manage-account-settings/require-destination-tags.md
- page: docs/tutorials/how-tos/manage-account-settings/offline-account-setup.md
- page: docs/tutorials/how-tos/manage-account-settings/use-tickets.md
- page: docs/tutorials/how-tos/use-specialized-payment-types/index.md
expanded: false
items:
- page: docs/tutorials/http-websocket-apis/build-apps/monitor-incoming-payments-with-websocket.md
- label: Protocol Development
items:
- page: docs/tutorials/how-tos/use-specialized-payment-types/use-escrows/index.md
expanded: false
items:
- page: docs/tutorials/how-tos/use-specialized-payment-types/use-escrows/send-a-time-held-escrow.md
- page: docs/tutorials/how-tos/use-specialized-payment-types/use-escrows/send-a-conditionally-held-escrow.md
- page: docs/tutorials/how-tos/use-specialized-payment-types/use-escrows/cancel-an-expired-escrow.md
- page: docs/tutorials/how-tos/use-specialized-payment-types/use-escrows/look-up-escrows.md
- page: docs/tutorials/how-tos/use-specialized-payment-types/use-escrows/use-an-escrow-as-a-smart-contract.md
- page: docs/tutorials/how-tos/use-specialized-payment-types/use-payment-channels/index.md
expanded: false
items:
- page: docs/tutorials/how-tos/use-specialized-payment-types/use-payment-channels/open-a-payment-channel-to-enable-an-inter-exchange-network.md
- page: docs/tutorials/how-tos/use-specialized-payment-types/use-checks/index.md
expanded: false
items:
- page: docs/tutorials/how-tos/use-specialized-payment-types/use-checks/send-a-check.md
- page: docs/tutorials/how-tos/use-specialized-payment-types/use-checks/cash-a-check-for-an-exact-amount.md
- page: docs/tutorials/how-tos/use-specialized-payment-types/use-checks/cash-a-check-for-a-flexible-amount.md
- page: docs/tutorials/how-tos/use-specialized-payment-types/use-checks/cancel-a-check.md
- page: docs/tutorials/how-tos/use-specialized-payment-types/use-checks/look-up-checks.md
- page: docs/tutorials/how-tos/use-tokens/index.md
expanded: false
items:
- page: docs/tutorials/how-tos/testing-devnet-features.md
items:
- page: docs/tutorials/how-tos/use-tokens/issue-a-fungible-token.md
- page: docs/tutorials/how-tos/use-tokens/trade-in-the-decentralized-exchange.md
- page: docs/tutorials/how-tos/use-tokens/enable-no-freeze.md
- page: docs/tutorials/how-tos/use-tokens/enact-global-freeze.md
- page: docs/tutorials/how-tos/use-tokens/freeze-a-trust-line.md
- page: docs/tutorials/how-tos/use-tokens/create-an-automated-market-maker.md
- page: docs/tutorials/how-tos/use-xrpl-sidechains/index.md
expanded: false
items:
- page: docs/tutorials/how-tos/use-xrpl-sidechains/set-up-xrp-xrp-bridge.md
- page: docs/tutorials/how-tos/use-xrpl-sidechains/set-up-iou-iou-bridge.md
- page: docs/tutorials/how-tos/use-xrpl-sidechains/submit-cross-chain-transaction.md
- page: docs/tutorials/how-tos/testing-devnet-features.md
- page: docs/references/index.md
labelTranslationKey: sidebar.docs.references
expanded: false
@@ -319,8 +365,8 @@
- page: docs/references/protocol/ledger-data/ledger-entry-types/nftokenpage.md
- page: docs/references/protocol/ledger-data/ledger-entry-types/offer.md
- page: docs/references/protocol/ledger-data/ledger-entry-types/oracle.md
- page: docs/references/protocol/ledger-data/ledger-entry-types/paychannel.md
- page: docs/references/protocol/ledger-data/ledger-entry-types/permissioneddomain.md
- page: docs/references/protocol/ledger-data/ledger-entry-types/paychannel.md
- page: docs/references/protocol/ledger-data/ledger-entry-types/ripplestate.md
- page: docs/references/protocol/ledger-data/ledger-entry-types/signerlist.md
- page: docs/references/protocol/ledger-data/ledger-entry-types/ticket.md
@@ -438,7 +484,6 @@
- page: docs/references/http-websocket-apis/api-conventions/rate-limiting.md
- page: docs/references/http-websocket-apis/api-conventions/rippled-server-states.md
- page: docs/references/http-websocket-apis/api-conventions/ctid.md
- page: docs/references/http-websocket-apis/api-conventions/ledger-entry-short-names.md
- page: docs/references/http-websocket-apis/public-api-methods/index.md
expanded: false
items:
@@ -703,5 +748,5 @@
- page: resources/contribute-documentation/documentation-translations.md
- page: resources/contribute-documentation/creating-diagrams.md
- page: resources/contribute-documentation/tutorial-guidelines.md
- page: resources/contribute-documentation/tutorial-structure.md
- page: resources/contribute-documentation/tutorial-template.md
- page: resources/contribute-blog/index.md

File diff suppressed because one or more lines are too long

Binary file not shown.

Before

Width:  |  Height:  |  Size: 61 KiB

View File

@@ -36,32 +36,33 @@
left: 0px;
}
.card-date {
#card-date {
color: $gray-400;
}
.hero-post-date {
.post-date {
text-decoration: overline solid #32E685 10%;
}
@each $category in "general", "developer_reflections", "amendments",
"case_study", "advisories", "release_notes", "development",
"gateway_bulletins", "features", "security" {
.#{$category} .category-list {
img {
#category-list {
@each $category in "general", "developer_reflections", "amendments",
"advisories", "release_notes", "development", "gateway_bulletins", "features", "security"
{
##{$category} {
content: url("../img/blog/#{$category}.png");
max-width: 100%;
width: 100%;
}
.label{
width: fit-content;
}
}
.label{
width: fit-content;
}
}
// Add styles to ensure proper wrapping on tablet sizes
@media (min-width: 768px) and (max-width: 991px) {
.category-list {
#category-list {
display: block;
img {

View File

@@ -385,7 +385,6 @@
&.label-use-developer_tooling,
&.label-use-payments,
&.blog-category-developer_reflections,
&.blog-category-case_study,
&.chip-blue {
@include chip-blue;
}