Skip to content

Commit ec1f33d

Browse files
authored
Merge branch 'master' into refactor_payment_modular_tuts
2 parents c7a11da + e6add92 commit ec1f33d

File tree

27 files changed

+730
-140
lines changed

27 files changed

+730
-140
lines changed

@theme/components/Navbar/AlgoliaSearch.tsx

Lines changed: 0 additions & 17 deletions
This file was deleted.

@theme/components/Navbar/Navbar.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { LanguagePicker } from "@redocly/theme/components/LanguagePicker/Languag
44
import { slugify } from "../../helpers";
55
import { Link } from "@redocly/theme/components/Link/Link";
66
import { ColorModeSwitcher } from "@redocly/theme/components/ColorModeSwitcher/ColorModeSwitcher";
7-
import { AlgoliaSearch } from "./AlgoliaSearch";
7+
import { Search } from "@redocly/theme/components/Search/Search";
88
import arrowUpRight from "../../../static/img/icons/arrow-up-right-custom.svg";
99

1010
// @ts-ignore
@@ -139,7 +139,7 @@ export function Navbar(props) {
139139
<NavItems>
140140
{navItems}
141141
<div id="topnav-search" className="nav-item search">
142-
<AlgoliaSearch />
142+
<Search className="topnav-search"/>
143143
</div>
144144
<div id="topnav-language" className="nav-item">
145145
<LanguagePicker

@theme/markdoc/components.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ export function Badge(props: {
145145
}
146146
}
147147

148-
type TryItServer = 's1' | 's2' | 'xrplcluster' | 'testnet' | 'devnet'
148+
type TryItServer = 's1' | 's2' | 'xrplcluster' | 'testnet' | 'devnet' | 'testnet-clio' | 'devnet-clio'
149149

150150
export function TryIt(props: {
151151
method: string,
@@ -164,6 +164,10 @@ export function TryIt(props: {
164164
use_server = "?server=wss%3A%2F%2Fs.devnet.rippletest.net%3A51233%2F"
165165
} else if (props.server == 'testnet') {
166166
use_server = "?server=wss%3A%2F%2Fs.altnet.rippletest.net%3A51233%2F"
167+
} else if (props.server == 'testnet-clio') {
168+
use_server = "?server=wss%3A%2F%2Fclio.altnet.rippletest.net%3A51233%2F"
169+
} else if (props.server == 'devnet-clio') {
170+
use_server = "?server=wss%3A%2F%2Fclio.devnet.rippletest.net%3A51233%2F"
167171
}
168172
const to_path = `/resources/dev-tools/websocket-api-tool${use_server}#${props.method}`
169173
return (

_code-samples/build-a-browser-wallet/js/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
"https-browserify": "^1.0.0",
1111
"stream-browserify": "^3.0.0",
1212
"stream-http": "^3.2.0",
13-
"vite": "^4.5.13"
13+
"vite": "^4.5.14"
1414
},
1515
"dependencies": {
1616
"dotenv": "^16.0.3",

_code-samples/build-a-browser-wallet/js/yarn.lock

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -679,10 +679,10 @@ util-deprecate@^1.0.1, util-deprecate@~1.0.1:
679679
resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
680680
integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==
681681

682-
vite@^4.5.13:
683-
version "4.5.13"
684-
resolved "https://registry.yarnpkg.com/vite/-/vite-4.5.13.tgz#778534a947112c6c455e89737730fae5d458a294"
685-
integrity sha512-Hgp8IF/yZDzKsN1hQWOuQZbrKiaFsbQud+07jJ8h9m9PaHWkpvZ5u55Xw5yYjWRXwRQ4jwFlJvY7T7FUJG9MCA==
682+
vite@^4.5.14:
683+
version "4.5.14"
684+
resolved "https://registry.yarnpkg.com/vite/-/vite-4.5.14.tgz#2e652bc1d898265d987d6543ce866ecd65fa4086"
685+
integrity sha512-+v57oAaoYNnO3hIu5Z/tJRZjq5aHM2zDve9YZ8HngVHbhk66RStobhb1sqPMIPEleV6cNKYK4eGrAbE9Ulbl2g==
686686
dependencies:
687687
esbuild "^0.18.10"
688688
postcss "^8.4.27"

_code-samples/issue-credentials/js/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,6 @@
1616
"express": "^5.1.0",
1717
"inquirer": "^12.5.2",
1818
"morgan": "^1.10.0",
19-
"xrpl": "^4.2.0"
19+
"xrpl": "^4.2.5"
2020
}
2121
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# Verify Credential - Javascript sample code
2+
3+
Verifies that a specific credential exists on the XRPL and is valid.
4+
5+
Quick install & usage:
6+
7+
```sh
8+
npm install
9+
```
10+
11+
`verify_credential.js` can also be used as a commandline utility. Full usage statement:
12+
13+
```sh
14+
$ ./verify_credential.js -h
15+
16+
Usage: verify-credential [options] [issuer] [subject] [credential_type]
17+
18+
Verify an XRPL credential
19+
20+
Arguments:
21+
issuer Credential issuer address as base58 (default:
22+
"rEzikzbnH6FQJ2cCr4Bqmf6c3jyWLzkonS")
23+
subject Credential subject (holder) address as base58 (default:
24+
"rsYhHbanGpnYe3M6bsaMeJT5jnLTfDEzoA")
25+
credential_type Credential type as string. (default: "my_credential")
26+
27+
Options:
28+
-b, --binary Use binary (hexadecimal) for credential_type
29+
-n, --network <network> {devnet,testnet,mainnet} Use the specified network for lookup (default: "devnet")
30+
-q, --quiet Don't print log messages
31+
-h, --help display help for command
32+
```
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
{
2+
"name": "issuer_service",
3+
"version": "1.0.0",
4+
"description": "",
5+
"main": "verify_credential.js",
6+
"scripts": {
7+
"test": "echo \"Error: no test specified\" && exit 1"
8+
},
9+
"keywords": [],
10+
"author": "",
11+
"license": "ISC",
12+
"type": "module",
13+
"dependencies": {
14+
"commander": "^13.1.0",
15+
"winston": "^3.17.0",
16+
"xrpl": "^4.2.5"
17+
}
18+
}
Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
#!/usr/bin/env node
2+
3+
import { Command } from "commander";
4+
import { Client, rippleTimeToISOTime, convertStringToHex } from "xrpl";
5+
import winston from "winston";
6+
7+
// Set up logging --------------------------------------------------------------
8+
// Use WARNING by default in case verify_credential is called from elsewhere.
9+
const logger = winston.createLogger({
10+
level: "warn",
11+
transports: [new winston.transports.Console()],
12+
format: winston.format.simple(),
13+
});
14+
15+
// Define an error to throw when XRPL lookup fails unexpectedly
16+
class XRPLLookupError extends Error {
17+
constructor(error) {
18+
super("XRPL look up error");
19+
this.name = "XRPLLookupError";
20+
this.body = error;
21+
}
22+
}
23+
24+
const CREDENTIAL_REGEX = /^[0-9A-F]{2,128}$/;
25+
// See https://xrpl.org/docs/references/protocol/ledger-data/ledger-entry-types/credential#credential-flags
26+
// to learn more about the lsfAccepted flag.
27+
const LSF_ACCEPTED = 0x00010000;
28+
29+
async function verifyCredential(client, issuer, subject, credentialType, binary=false) {
30+
/**
31+
* Check whether an XRPL account holds a specified credential,
32+
* as of the most recently validated ledger.
33+
* Parameters:
34+
* client - Client for interacting with rippled servers.
35+
* issuer - Address of the credential issuer, in base58.
36+
* subject - Address of the credential holder/subject, in base58.
37+
* credentialType - Credential type to check for as a string,
38+
* which will be encoded as UTF-8 (1-128 characters long).
39+
* binary - Specifies that the credential type is provided in hexadecimal format.
40+
* You must provide the credential_type as input.
41+
* Returns True if the account holds the specified, valid credential.
42+
* Returns False if the credential is missing, expired, or not accepted.
43+
*/
44+
45+
// Encode credentialType as uppercase hex, if needed
46+
let credentialTypeHex = "";
47+
if (binary) {
48+
credentialTypeHex = credentialType.toUpperCase();
49+
} else {
50+
credentialTypeHex = convertStringToHex(credentialType).toUpperCase();
51+
logger.info(`Encoded credential_type as hex: ${credentialTypeHex}`);
52+
}
53+
54+
if (credentialTypeHex.length % 2 !== 0 || !CREDENTIAL_REGEX.test(credentialTypeHex)) {
55+
// Hexadecimal is always 2 chars per byte, so an odd length is invalid.
56+
throw new Error("Credential type must be 128 characters as hexadecimal.");
57+
}
58+
59+
// Perform XRPL lookup of Credential ledger entry --------------------------
60+
const ledgerEntryRequest = {
61+
command: "ledger_entry",
62+
credential: {
63+
subject: subject,
64+
issuer: issuer,
65+
credential_type: credentialTypeHex,
66+
},
67+
ledger_index: "validated",
68+
};
69+
logger.info("Looking up credential...");
70+
logger.info(JSON.stringify(ledgerEntryRequest, null, 2));
71+
72+
let xrplResponse;
73+
try {
74+
xrplResponse = await client.request(ledgerEntryRequest);
75+
} catch (err) {
76+
if (err.data?.error === "entryNotFound") {
77+
logger.info("Credential was not found");
78+
return false;
79+
} else {
80+
// Other errors, for example invalidly specified addresses.
81+
throw new XRPLLookupError(err?.data || err);
82+
}
83+
}
84+
85+
const credential = xrplResponse.result.node;
86+
logger.info("Found credential:");
87+
logger.info(JSON.stringify(credential, null, 2));
88+
89+
// Check if the credential has been accepted ---------------------------
90+
if (!(credential.Flags & LSF_ACCEPTED)) {
91+
logger.info("Credential is not accepted.");
92+
return false
93+
}
94+
95+
// Confirm that the credential is not expired ------------------------------
96+
if (credential.Expiration) {
97+
const expirationTime = rippleTimeToISOTime(credential.Expiration);
98+
logger.info(`Credential has expiration: ${expirationTime}`);
99+
logger.info("Looking up validated ledger to check for expiration.");
100+
101+
let ledgerResponse;
102+
try {
103+
ledgerResponse = await client.request({
104+
command: "ledger",
105+
ledger_index: "validated",
106+
});
107+
} catch (err) {
108+
throw new XRPLLookupError(err?.data || err);
109+
}
110+
111+
const closeTime = rippleTimeToISOTime(ledgerResponse.result.ledger.close_time);
112+
logger.info(`Most recent validated ledger is: ${closeTime}`);
113+
114+
if (new Date(closeTime) > new Date(expirationTime)) {
115+
logger.info("Credential is expired.");
116+
return false;
117+
}
118+
}
119+
120+
// Credential has passed all checks ---------------------------------------
121+
logger.info("Credential is valid.");
122+
return true;
123+
}
124+
125+
126+
// Commandline usage -----------------------------------------------------------
127+
async function main() {
128+
// Websocket URLs of public servers
129+
const NETWORKS = {
130+
devnet: "wss://s.devnet.rippletest.net:51233",
131+
testnet: "wss://s.altnet.rippletest.net:51233",
132+
mainnet: "wss://xrplcluster.com/",
133+
};
134+
135+
136+
// Parse arguments ---------------------------------------------------------
137+
let result = false
138+
const program = new Command();
139+
program
140+
.name("verify-credential")
141+
.description("Verify an XRPL credential")
142+
.argument("[issuer]", "Credential issuer address as base58", "rEzikzbnH6FQJ2cCr4Bqmf6c3jyWLzkonS")
143+
.argument("[subject]", "Credential subject (holder) address as base58", "rsYhHbanGpnYe3M6bsaMeJT5jnLTfDEzoA")
144+
.argument("[credential_type]", "Credential type as string.", "my_credential")
145+
.option("-b, --binary", "Use binary (hexadecimal) for credential_type")
146+
.option(
147+
`-n, --network <network> {${Object.keys(NETWORKS)}}`,
148+
"Use the specified network for lookup",
149+
(value) => {
150+
if (!Object.keys(NETWORKS).includes(value)) {
151+
throw new Error(`Must be one of: ${Object.keys(NETWORKS)}`);
152+
}
153+
return value;
154+
},
155+
"devnet"
156+
)
157+
.option("-q, --quiet", "Don't print log messages")
158+
// Call verify_credential with appropriate args ----------------------------
159+
.action(async (issuer, subject, credentialType, options) => {
160+
const client = new Client(NETWORKS[options.network]);
161+
await client.connect();
162+
163+
// Use INFO level by default when called from the commandline.
164+
if (!options.quiet) { logger.level = "info" }
165+
166+
// Commander.js automatically sets options.binary to a boolean:
167+
// - If you provide -b or --binary on the command line then options.binary = true
168+
// - If you do not provide it then options.binary = false
169+
result = await verifyCredential(client, issuer, subject, credentialType, options.binary);
170+
171+
await client.disconnect();
172+
});
173+
await program.parseAsync(process.argv);
174+
175+
// Return a nonzero exit code if credential verification failed -----------
176+
if (!result) {
177+
process.exit(1);
178+
}
179+
}
180+
181+
main().catch((err) => {
182+
console.error("Fatal startup error:", err);
183+
process.exit(1);
184+
});

docs/concepts/tokens/fungible-tokens/authorized-trust-lines.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ The Authorized Trust Lines feature enables issuers to create tokens that can onl
1313

1414
To use the Authorized Trust Lines feature, enable the **Require Auth** flag on your issuing account. While the setting is enabled, other accounts can only hold tokens you issue if you have authorized those accounts' trust lines to your issuing account.
1515

16-
You can authorize a trust line by sending a [TrustSet transaction][] from your issuing address, configuring the trust line between your account and the account to authorize. After you have authorized a trust line, you can never revoke that authorization. (You can, however, [freeze](freezes.md) that trust line if you need to.)
16+
You can authorize a trust line by sending a [TrustSet transaction][] from your issuing address, configuring the trust line between your account and the account to authorize. After you have authorized a trust line, you can't revoke that authorization, but the authorization status is reset if the trust line is automatically deleted for being otherwise in its default state. (You can, however, [freeze](freezes.md) that trust line if you need to.)
1717

1818
The transaction to authorize a trust line must be signed by the issuing address, which unfortunately means an increased risk exposure for that address.
1919

0 commit comments

Comments
 (0)