Skip to content

Commit 06071a4

Browse files
authored
introduce hex validation for domainID in Payment, OfferCreate txn (#3050)
* introduce hex validation for domainID in Payment, OfferCreate txn * fix: use ==null condition to cover undefined, null and NaN cases * Example snippets file
1 parent e3b7efd commit 06071a4

File tree

3 files changed

+236
-2
lines changed

3 files changed

+236
-2
lines changed
Lines changed: 230 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,230 @@
1+
import { AccountSetAsfFlags, Client, OfferCreateFlags } from '../../src'
2+
3+
const client = new Client('wss://s.devnet.rippletest.net:51233')
4+
5+
// This snippet walks us through the usage of permissioned DEX.
6+
async function permDEXExamples(): Promise<void> {
7+
await client.connect()
8+
9+
// creating wallets as prerequisite
10+
const { wallet: wallet1 } = await client.fundWallet(null, {
11+
usageContext: 'code snippets',
12+
})
13+
const { wallet: wallet2 } = await client.fundWallet(null, {
14+
usageContext: 'code snippets',
15+
})
16+
17+
const { wallet: issuerWallet } = await client.fundWallet(null, {
18+
usageContext: 'code snippets',
19+
})
20+
21+
// allow rippling on the issuer wallet -- required for crossing of IOU offers
22+
await client.submitAndWait(
23+
{
24+
TransactionType: 'AccountSet',
25+
Account: issuerWallet.classicAddress,
26+
SetFlag: AccountSetAsfFlags.asfDefaultRipple,
27+
},
28+
{
29+
wallet: issuerWallet,
30+
},
31+
)
32+
33+
// create a credential for wallet1, issued by the issuerWallet
34+
await client.submitAndWait(
35+
{
36+
TransactionType: 'CredentialCreate',
37+
Subject: wallet1.classicAddress,
38+
Account: issuerWallet.classicAddress,
39+
CredentialType: 'ABCD',
40+
},
41+
{
42+
wallet: issuerWallet,
43+
},
44+
)
45+
46+
// create a credential for wallet2, issued by the issuerWallet
47+
await client.submitAndWait(
48+
{
49+
TransactionType: 'CredentialCreate',
50+
Subject: wallet2.classicAddress,
51+
Account: issuerWallet.classicAddress,
52+
CredentialType: 'ABCD',
53+
},
54+
{
55+
wallet: issuerWallet,
56+
},
57+
)
58+
59+
// accept the credential for wallet1
60+
await client.submitAndWait(
61+
{
62+
TransactionType: 'CredentialAccept',
63+
Account: wallet1.classicAddress,
64+
Issuer: issuerWallet.classicAddress,
65+
CredentialType: 'ABCD',
66+
},
67+
{
68+
wallet: wallet1,
69+
},
70+
)
71+
72+
// accept the credential for wallet2
73+
await client.submitAndWait(
74+
{
75+
TransactionType: 'CredentialAccept',
76+
Account: wallet2.classicAddress,
77+
Issuer: issuerWallet.classicAddress,
78+
CredentialType: 'ABCD',
79+
},
80+
{
81+
wallet: wallet2,
82+
},
83+
)
84+
85+
// issuerWallet creates a permissioned domain with the credential type 'ABCD'
86+
await client.submitAndWait(
87+
{
88+
TransactionType: 'PermissionedDomainSet',
89+
Account: issuerWallet.classicAddress,
90+
AcceptedCredentials: [
91+
{
92+
Credential: {
93+
CredentialType: 'ABCD',
94+
Issuer: issuerWallet.classicAddress,
95+
},
96+
},
97+
],
98+
},
99+
{
100+
wallet: issuerWallet,
101+
},
102+
)
103+
104+
const result = await client.request({
105+
command: 'account_objects',
106+
account: issuerWallet.classicAddress,
107+
type: 'permissioned_domain',
108+
})
109+
110+
const pd_ledger_object = result.result.account_objects[0]
111+
112+
// create a payment inside the domain
113+
await client.submitAndWait(
114+
{
115+
TransactionType: 'Payment',
116+
Account: wallet1.classicAddress,
117+
Amount: '10000',
118+
Destination: wallet2.classicAddress,
119+
DomainID: pd_ledger_object.index,
120+
},
121+
{
122+
wallet: wallet1,
123+
},
124+
)
125+
126+
// establish trust line for USD IOU Token
127+
await client.submitAndWait(
128+
{
129+
TransactionType: 'TrustSet',
130+
Account: wallet1.classicAddress,
131+
LimitAmount: {
132+
currency: 'USD',
133+
issuer: issuerWallet.classicAddress,
134+
value: '10000',
135+
},
136+
},
137+
{
138+
wallet: wallet1,
139+
},
140+
)
141+
142+
await client.submitAndWait(
143+
{
144+
TransactionType: 'TrustSet',
145+
Account: wallet2.classicAddress,
146+
LimitAmount: {
147+
currency: 'USD',
148+
issuer: issuerWallet.classicAddress,
149+
value: '10000',
150+
},
151+
},
152+
{
153+
wallet: wallet2,
154+
},
155+
)
156+
157+
// ensure sufficient funds in wallet1 to pay for the offer
158+
await client.submitAndWait(
159+
{
160+
TransactionType: 'Payment',
161+
Account: issuerWallet.classicAddress,
162+
Amount: {
163+
currency: 'USD',
164+
issuer: issuerWallet.classicAddress,
165+
value: '1000',
166+
},
167+
Destination: wallet1.classicAddress,
168+
},
169+
{
170+
wallet: issuerWallet,
171+
},
172+
)
173+
174+
await client.submitAndWait(
175+
{
176+
TransactionType: 'Payment',
177+
Account: issuerWallet.classicAddress,
178+
Amount: {
179+
currency: 'USD',
180+
issuer: issuerWallet.classicAddress,
181+
value: '1000',
182+
},
183+
Destination: wallet2.classicAddress,
184+
},
185+
{
186+
wallet: issuerWallet,
187+
},
188+
)
189+
190+
// create an offer inside the domain
191+
await client.submitAndWait(
192+
{
193+
TransactionType: 'OfferCreate',
194+
Account: wallet1.classicAddress,
195+
TakerGets: '10',
196+
TakerPays: {
197+
currency: 'USD',
198+
issuer: issuerWallet.classicAddress,
199+
value: '10',
200+
},
201+
Flags: OfferCreateFlags.tfHybrid,
202+
DomainID: pd_ledger_object.index,
203+
},
204+
{
205+
wallet: wallet1,
206+
},
207+
)
208+
209+
const offerTxResponse2 = await client.submitAndWait(
210+
{
211+
TransactionType: 'OfferCreate',
212+
Account: wallet2.classicAddress,
213+
TakerPays: '10',
214+
TakerGets: {
215+
currency: 'USD',
216+
issuer: issuerWallet.classicAddress,
217+
value: '10',
218+
},
219+
Flags: OfferCreateFlags.tfHybrid,
220+
DomainID: pd_ledger_object.index,
221+
},
222+
{
223+
wallet: wallet2,
224+
},
225+
)
226+
console.log('offerTxResponse2: ', offerTxResponse2)
227+
228+
await client.disconnect()
229+
}
230+
void permDEXExamples()

packages/xrpl/src/models/transactions/common.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -694,5 +694,9 @@ const _DOMAIN_ID_LENGTH = 64
694694
* @returns true if the domainID is a valid 64-character string, false otherwise
695695
*/
696696
export function isDomainID(domainID: unknown): domainID is string {
697-
return isString(domainID) && domainID.length === _DOMAIN_ID_LENGTH
697+
return (
698+
isString(domainID) &&
699+
domainID.length === _DOMAIN_ID_LENGTH &&
700+
isHex(domainID)
701+
)
698702
}

packages/xrpl/src/models/transactions/offerCreate.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,7 @@ export function validateOfferCreate(tx: Record<string, unknown>): void {
158158
})
159159

160160
if (
161-
tx.DomainID === undefined &&
161+
tx.DomainID == null &&
162162
hasFlag(tx, OfferCreateFlags.tfHybrid, 'tfHybrid')
163163
) {
164164
throw new ValidationError(

0 commit comments

Comments
 (0)