@@ -15,6 +15,7 @@ import * as xrpl from 'xrpl';
1515import { XrpToken } from '../../src' ;
1616import * as testData from '../resources/xrp' ;
1717import { SIGNER_BACKUP , SIGNER_BITGO , SIGNER_USER } from '../resources/xrp' ;
18+ import { getMptBuilderFactory } from './getBuilderFactory' ;
1819
1920nock . disableNetConnect ( ) ;
2021
@@ -202,6 +203,41 @@ describe('XRP:', function () {
202203 ( signedTransaction . Signers as Array < string > ) . length . should . equal ( 2 ) ;
203204 } ) ;
204205
206+ it ( 'should multi-sign an MPTokenAuthorize transaction using the xrpl codec (encodeForMultiSigning)' , async function ( ) {
207+ // Build an unsigned MPTokenAuthorize tx using the builder so we get a real XRPL-encoded hex.
208+ // This exercises the ripple.ts encodeForMultiSigning path via the xrpl codec (v2.7.0)
209+ // which supports the MPTokenAuthorize transaction type absent in ripple-binary-codec v2.1.0.
210+ const factory = getMptBuilderFactory ( testData . MPT_ISSUANCE_ID ) ;
211+ const sender = testData . TEST_MULTI_SIG_ACCOUNT . address . split ( '?' ) [ 0 ] ; // strip destination tag
212+
213+ const builder = factory . getMPTokenAuthorizeBuilder ( ) ;
214+ builder . sender ( sender ) ;
215+ builder . mptIssuanceId ( testData . MPT_ISSUANCE_ID ) ;
216+ builder . sequence ( 1600000 ) ;
217+ builder . fee ( '12' ) ;
218+ builder . flags ( 2147483648 ) ;
219+
220+ const unsignedTx = await builder . build ( ) ;
221+ const unsignedHex = unsignedTx . toBroadcastFormat ( ) ;
222+
223+ // Sign with first signer
224+ const firstSigned = ripple . signWithPrivateKey ( unsignedHex , SIGNER_USER . prv , {
225+ signAs : SIGNER_USER . address ,
226+ } ) ;
227+
228+ // Add second signature
229+ const fullySigned = ripple . signWithPrivateKey ( firstSigned . signedTransaction , SIGNER_BITGO . prv , {
230+ signAs : SIGNER_BITGO . address ,
231+ } ) ;
232+
233+ // Must use xrpl.decode (ripple-binary-codec v2.7.0) — the standalone
234+ // ripple-binary-codec v2.1.0 doesn't know the MPTokenAuthorize type.
235+ const decoded = xrpl . decode ( fullySigned . signedTransaction ) ;
236+ ( decoded . TransactionType as string ) . should . equal ( 'MPTokenAuthorize' ) ;
237+ assert ( Array . isArray ( decoded . Signers ) ) ;
238+ ( decoded . Signers as Array < unknown > ) . length . should . equal ( 2 ) ;
239+ } ) ;
240+
205241 it ( 'should be able to cosign XRP transaction in any form' , function ( ) {
206242 const unsignedTxHex =
207243 '120000228000000024000000072E00000000201B0018D07161400000000003DE2968400000000000002D8114726D0D8A26568D5D9680AC80577C912236717191831449EE221CCACC4DD2BF8862B22B0960A84FC771D9' ;
@@ -965,5 +1001,41 @@ describe('XRP:', function () {
9651001 { message : 'Invalid token issuer or currency on token enablement tx' }
9661002 ) ;
9671003 } ) ;
1004+
1005+ it ( 'should pass verifyMptTxType for a valid MPTokenAuthorize prebuild' , async function ( ) {
1006+ const factory = getMptBuilderFactory ( testData . MPT_ISSUANCE_ID ) ;
1007+ const sender = testData . TEST_MULTI_SIG_ACCOUNT . address . split ( '?' ) [ 0 ] ;
1008+
1009+ const builder = factory . getMPTokenAuthorizeBuilder ( ) ;
1010+ builder . sender ( sender ) ;
1011+ builder . mptIssuanceId ( testData . MPT_ISSUANCE_ID ) ;
1012+ builder . sequence ( 1600000 ) ;
1013+ builder . fee ( '12' ) ;
1014+ builder . flags ( 2147483648 ) ;
1015+
1016+ const txHex = ( await builder . build ( ) ) . toBroadcastFormat ( ) ;
1017+
1018+ const result = await basecoin . verifyTransaction ( {
1019+ txParams : { type : 'enableMpt' } ,
1020+ txPrebuild : { txHex } ,
1021+ verification : { verifyTokenEnablement : true } ,
1022+ } ) ;
1023+ result . should . equal ( true ) ;
1024+ } ) ;
1025+
1026+ it ( 'should reject enableMpt when on-chain type is not MPTokenAuthorize' , async function ( ) {
1027+ // TrustSet hex — wrong on-chain type for an enableMpt intent
1028+ const txHex = `{"TransactionType":"TrustSet","Account":"rBSpCz8PafXTJHppDcNnex7dYnbe3tSuFG","LimitAmount":{"currency":"524C555344000000000000000000000000000000","issuer":"rQhWct2fv4Vc4KRjRgMrxa8xPN9Zx9iLKV","value":"99999999"},"Flags":2147483648,"Fee":"45","Sequence":7}` ;
1029+
1030+ await assert . rejects (
1031+ async ( ) =>
1032+ basecoin . verifyTransaction ( {
1033+ txParams : { type : 'enableMpt' } ,
1034+ txPrebuild : { txHex } ,
1035+ verification : { verifyTokenEnablement : true } ,
1036+ } ) ,
1037+ { message : 'tx type TrustSet does not match expected type MPTokenAuthorize' }
1038+ ) ;
1039+ } ) ;
9681040 } ) ;
9691041} ) ;
0 commit comments