Skip to content

Commit effe757

Browse files
Support NFTokenMintOffer (#2875)
* Support NFTokenMintOffer * Add Integration test * Update packages/xrpl/HISTORY.md Co-authored-by: achowdhry-ripple <achowdhry@ripple.com> * Update packages/xrpl/src/models/transactions/NFTokenMint.ts Co-authored-by: achowdhry-ripple <achowdhry@ripple.com> * grouped valid tests --------- Co-authored-by: achowdhry-ripple <achowdhry@ripple.com>
1 parent 066e670 commit effe757

File tree

4 files changed

+157
-1
lines changed

4 files changed

+157
-1
lines changed

packages/xrpl/HISTORY.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@ Subscribe to [the **xrpl-announce** mailing list](https://groups.google.com/g/xr
44

55
## Unreleased
66

7+
### Added
8+
* Support for `NFTokenMintOffer` (XLS-52)
9+
710
### Fixed
811
* `OracleSet` transaction accepts hexadecimal string values for `AssetPrice` field
912
* `TransactionStream` model includes `hash` field in APIv2

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

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
import { ValidationError } from '../../errors'
2+
import { Amount } from '../common'
23
import { isHex } from '../utils'
34

45
import {
56
Account,
67
BaseTransaction,
78
GlobalFlags,
89
isAccount,
10+
isAmount,
11+
isNumber,
912
validateBaseTransaction,
1013
validateOptionalField,
1114
} from './common'
@@ -104,12 +107,34 @@ export interface NFTokenMint extends BaseTransaction {
104107
* set to `undefined` value if you do not use it.
105108
*/
106109
URI?: string | null
110+
/**
111+
* Indicates the amount expected for the Token.
112+
*
113+
* The amount can be zero. This would indicate that the account is giving
114+
* the token away free, either to anyone at all, or to the account identified
115+
* by the Destination field.
116+
*/
117+
Amount?: Amount
118+
/**
119+
* Indicates the time after which the offer will no longer
120+
* be valid. The value is the number of seconds since the
121+
* Ripple Epoch.
122+
*/
123+
Expiration?: number
124+
/**
125+
* If present, indicates that this offer may only be
126+
* accepted by the specified account. Attempts by other
127+
* accounts to accept this offer MUST fail.
128+
*/
129+
Destination?: Account
107130
Flags?: number | NFTokenMintFlagsInterface
108131
}
109132

110133
export interface NFTokenMintMetadata extends TransactionMetadataBase {
111134
// rippled 1.11.0 or later
112135
nftoken_id?: string
136+
// if Amount is present
137+
offer_id?: string
113138
}
114139

115140
/**
@@ -140,4 +165,16 @@ export function validateNFTokenMint(tx: Record<string, unknown>): void {
140165
if (tx.NFTokenTaxon == null) {
141166
throw new ValidationError('NFTokenMint: missing field NFTokenTaxon')
142167
}
168+
169+
if (tx.Amount == null) {
170+
if (tx.Expiration != null || tx.Destination != null) {
171+
throw new ValidationError(
172+
'NFTokenMint: Amount is required when Expiration or Destination is present',
173+
)
174+
}
175+
}
176+
177+
validateOptionalField(tx, 'Amount', isAmount)
178+
validateOptionalField(tx, 'Expiration', isNumber)
179+
validateOptionalField(tx, 'Destination', isAccount)
143180
}

packages/xrpl/test/integration/transactions/nftokenMint.test.ts

Lines changed: 65 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ import {
66
NFTokenMint,
77
TransactionMetadata,
88
TxRequest,
9+
unixTimeToRippleTime,
10+
Wallet,
11+
xrpToDrops,
912
} from '../../../src'
1013
import { hashSignedTx } from '../../../src/utils/hashes'
1114
import serverUrl from '../serverUrl'
@@ -14,16 +17,18 @@ import {
1417
teardownClient,
1518
type XrplIntegrationTestContext,
1619
} from '../setup'
17-
import { testTransaction } from '../utils'
20+
import { generateFundedWallet, testTransaction } from '../utils'
1821

1922
// how long before each test case times out
2023
const TIMEOUT = 20000
2124

2225
describe('NFTokenMint', function () {
2326
let testContext: XrplIntegrationTestContext
27+
let destinationWallet: Wallet
2428

2529
beforeEach(async () => {
2630
testContext = await setupClient(serverUrl)
31+
destinationWallet = await generateFundedWallet(testContext.client)
2732
})
2833
afterEach(async () => teardownClient(testContext))
2934

@@ -91,4 +96,63 @@ describe('NFTokenMint', function () {
9196
},
9297
TIMEOUT,
9398
)
99+
100+
it(
101+
'test with Amount',
102+
async function () {
103+
const tx: NFTokenMint = {
104+
TransactionType: 'NFTokenMint',
105+
Account: testContext.wallet.address,
106+
URI: convertStringToHex('https://www.google.com'),
107+
NFTokenTaxon: 0,
108+
Amount: xrpToDrops(1),
109+
Expiration: unixTimeToRippleTime(Date.now() + 1000 * 60 * 60 * 24),
110+
Destination: destinationWallet.address,
111+
}
112+
const response = await testTransaction(
113+
testContext.client,
114+
tx,
115+
testContext.wallet,
116+
)
117+
assert.equal(response.type, 'response')
118+
119+
const txRequest: TxRequest = {
120+
command: 'tx',
121+
transaction: hashSignedTx(response.result.tx_blob),
122+
}
123+
const txResponse = await testContext.client.request(txRequest)
124+
125+
assert.equal(
126+
(txResponse.result.meta as TransactionMetadata).TransactionResult,
127+
'tesSUCCESS',
128+
)
129+
130+
const nftokenID =
131+
getNFTokenID(
132+
txResponse.result.meta as TransactionMetadata<NFTokenMint>,
133+
) ?? 'undefined'
134+
135+
const nftokenOfferID = (
136+
txResponse.result.meta as TransactionMetadata<NFTokenMint>
137+
).offer_id
138+
139+
const sellOffers = await testContext.client.request({
140+
command: 'nft_sell_offers',
141+
nft_id: nftokenID,
142+
})
143+
144+
const existsOffer = sellOffers.result.offers.some(
145+
(value) => value.nft_offer_index === nftokenOfferID,
146+
)
147+
148+
assert.isTrue(
149+
existsOffer,
150+
`Expected to exist an offer for NFT with NFTokenID ${nftokenID} but did not find it.
151+
\n\nHere's what was returned from 'nft_sell_offers': ${JSON.stringify(
152+
sellOffers,
153+
)}`,
154+
)
155+
},
156+
TIMEOUT,
157+
)
94158
})

packages/xrpl/test/models/NFTokenMint.test.ts

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,22 @@ describe('NFTokenMint', function () {
3131
assert.doesNotThrow(() => validate(validNFTokenMint))
3232
})
3333

34+
it(`verifies valid NFTokenMint with Amount, Destination and Expiration`, function () {
35+
const valid = {
36+
TransactionType: 'NFTokenMint',
37+
Account: 'rWYkbWkCeg8dP6rXALnjgZSjjLyih5NXm',
38+
Fee: '5000000',
39+
Sequence: 2470665,
40+
NFTokenTaxon: 0,
41+
Issuer: 'r9LqNeG6qHxjeUocjvVki2XR35weJ9mZgQ',
42+
Amount: '1000000',
43+
Destination: 'rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn',
44+
Expiration: 123456,
45+
} as any
46+
47+
assert.doesNotThrow(() => validate(valid))
48+
})
49+
3450
it(`throws w/ missing NFTokenTaxon`, function () {
3551
const invalid = {
3652
TransactionType: 'NFTokenMint',
@@ -109,4 +125,40 @@ describe('NFTokenMint', function () {
109125
'NFTokenMint: URI must be in hex format',
110126
)
111127
})
128+
129+
it(`throws when Amount is null but Expiration is present`, function () {
130+
const invalid = {
131+
TransactionType: 'NFTokenMint',
132+
Account: 'rWYkbWkCeg8dP6rXALnjgZSjjLyih5NXm',
133+
Fee: '5000000',
134+
Sequence: 2470665,
135+
NFTokenTaxon: 0,
136+
Issuer: 'r9LqNeG6qHxjeUocjvVki2XR35weJ9mZgQ',
137+
Expiration: 123456,
138+
} as any
139+
140+
assert.throws(
141+
() => validate(invalid),
142+
ValidationError,
143+
'NFTokenMint: Amount is required when Expiration or Destination is present',
144+
)
145+
})
146+
147+
it(`throws when Amount is null but Destination is present`, function () {
148+
const invalid = {
149+
TransactionType: 'NFTokenMint',
150+
Account: 'rWYkbWkCeg8dP6rXALnjgZSjjLyih5NXm',
151+
Fee: '5000000',
152+
Sequence: 2470665,
153+
NFTokenTaxon: 0,
154+
Issuer: 'r9LqNeG6qHxjeUocjvVki2XR35weJ9mZgQ',
155+
Destination: 'rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn',
156+
} as any
157+
158+
assert.throws(
159+
() => validate(invalid),
160+
ValidationError,
161+
'NFTokenMint: Amount is required when Expiration or Destination is present',
162+
)
163+
})
112164
})

0 commit comments

Comments
 (0)