-
Notifications
You must be signed in to change notification settings - Fork 8
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Adds sign transaction functionality to xrp app (#130)
- Loading branch information
1 parent
a036014
commit 66749b9
Showing
15 changed files
with
940 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,4 @@ | ||
export * from './getPublicKeys'; | ||
export * from './getUserVerifiedPublicKey'; | ||
export * from './runGetPublicKeys'; | ||
export * from './signTxn'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
import { ISDK } from '@cypherock/sdk-core'; | ||
import { | ||
createStatusListener, | ||
assert, | ||
hexToUint8Array, | ||
uint8ArrayToHex, | ||
createLoggerWithPrefix, | ||
} from '@cypherock/sdk-utils'; | ||
import { APP_VERSION } from '../../constants/appId'; | ||
import { | ||
SeedGenerationStatus, | ||
SignTxnStatus, | ||
} from '../../proto/generated/types'; | ||
import { | ||
assertOrThrowInvalidResult, | ||
getXrpLib, | ||
OperationHelper, | ||
logger as rootLogger, | ||
} from '../../utils'; | ||
import { ISignTxnParams, ISignTxnResult, SignTxnEvent } from './types'; | ||
|
||
export * from './types'; | ||
|
||
const logger = createLoggerWithPrefix(rootLogger, 'SignTxn'); | ||
|
||
export const signTxn = async ( | ||
sdk: ISDK, | ||
params: ISignTxnParams, | ||
): Promise<ISignTxnResult> => { | ||
assert(params, 'Params should be defined'); | ||
assert(params.walletId, 'walletId should be defined'); | ||
assert(params.txn, 'txn should be defined'); | ||
assert(typeof params.txn === 'object', 'txn should be an object'); | ||
assert( | ||
typeof params.txn.rawTxn === 'object', | ||
'txn.rawTxn should be an object', | ||
); | ||
assert( | ||
typeof params.txn.txnHex === 'string', | ||
'txn.txnHex should be a string', | ||
); | ||
assert(params.derivationPath, 'derivationPath should be defined'); | ||
assert( | ||
params.derivationPath.length === 5, | ||
'derivationPath should be equal to 5', | ||
); | ||
|
||
await sdk.checkAppCompatibility(APP_VERSION); | ||
|
||
const { onStatus, forceStatusUpdate } = createStatusListener({ | ||
enums: SignTxnEvent, | ||
operationEnums: SignTxnStatus, | ||
seedGenerationEnums: SeedGenerationStatus, | ||
onEvent: params.onEvent, | ||
logger, | ||
}); | ||
|
||
const helper = new OperationHelper({ | ||
sdk, | ||
queryKey: 'signTxn', | ||
resultKey: 'signTxn', | ||
onStatus, | ||
}); | ||
|
||
const txnBytes = hexToUint8Array(params.txn.txnHex); | ||
|
||
await helper.sendQuery({ | ||
initiate: { | ||
walletId: params.walletId, | ||
derivationPath: params.derivationPath, | ||
transactionSize: txnBytes.length, | ||
}, | ||
}); | ||
|
||
const { confirmation } = await helper.waitForResult(); | ||
assertOrThrowInvalidResult(confirmation); | ||
forceStatusUpdate(SignTxnEvent.CONFIRM); | ||
|
||
await helper.sendInChunks(txnBytes, 'txnData', 'dataAccepted'); | ||
|
||
await helper.sendQuery({ | ||
signature: {}, | ||
}); | ||
const result = await helper.waitForResult(); | ||
assertOrThrowInvalidResult(result.signature); | ||
|
||
forceStatusUpdate(SignTxnEvent.PIN_CARD); | ||
|
||
const signature = uint8ArrayToHex(result.signature.signature); | ||
|
||
let serializedTxn: string | undefined; | ||
|
||
if (params.serializeTxn) { | ||
const signedTransaction = { | ||
...params.txn.rawTxn, | ||
TxnSignature: signature, | ||
}; | ||
serializedTxn = getXrpLib().encode(signedTransaction); | ||
} | ||
|
||
return { | ||
signature, | ||
serializedTxn, | ||
}; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
import { Payment as PaymentTransaction } from 'xrpl'; | ||
|
||
export enum SignTxnEvent { | ||
INIT = 0, | ||
CONFIRM = 1, | ||
VERIFY = 2, | ||
PASSPHRASE = 3, | ||
PIN_CARD = 4, | ||
} | ||
|
||
export type SignTxnEventHandler = (event: SignTxnEvent) => void; | ||
|
||
export interface IUnsignedTransaction { | ||
rawTxn: PaymentTransaction; | ||
txnHex: string; | ||
} | ||
|
||
export interface ISignTxnParams { | ||
onEvent?: SignTxnEventHandler; | ||
|
||
walletId: Uint8Array; | ||
derivationPath: number[]; | ||
txn: IUnsignedTransaction; | ||
serializeTxn?: boolean; | ||
} | ||
|
||
export interface ISignTxnResult { | ||
signature: string; | ||
serializedTxn?: string; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,3 @@ | ||
export * from './runGetPublicKeys/types'; | ||
export * from './getUserVerifiedPublicKey/types'; | ||
export * from './signTxn/types'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
105 changes: 105 additions & 0 deletions
105
packages/app-xrp/tests/03.signTxn/__fixtures__/error.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
import { | ||
DeviceAppError, | ||
DeviceAppErrorType, | ||
deviceAppErrorTypeDetails, | ||
} from '@cypherock/sdk-interfaces'; | ||
import { ISignTxnTestCase } from './types'; | ||
import { queryToUint8Array, resultToUint8Array } from '../__helpers__'; | ||
import { ISignTxnParams } from '../../../src'; | ||
|
||
const commonParams: { | ||
params: ISignTxnParams; | ||
queries: { | ||
name: string; | ||
data: Uint8Array; | ||
}[]; | ||
} = { | ||
params: { | ||
walletId: new Uint8Array([ | ||
199, 89, 252, 26, 32, 135, 183, 211, 90, 220, 38, 17, 160, 103, 233, 62, | ||
110, 172, 92, 20, 35, 250, 190, 146, 62, 8, 53, 86, 128, 26, 3, 187, 121, | ||
64, | ||
]), | ||
derivationPath: [0x80000000 + 44, 0x80000000 + 144, 0x80000000, 0, 0], | ||
txn: { | ||
rawTxn: { | ||
TransactionType: 'Payment', | ||
Account: 'rQGDkQchoJxMSLZR7q9GwvY3iKtDqTUYNQ', | ||
Amount: '5000000', | ||
Destination: 'rEgfV7YeyG4YayQQufxaqDx4aUA93SidLb', | ||
Flags: 0, | ||
NetworkID: undefined, | ||
Sequence: 676674, | ||
Fee: '12', | ||
LastLedgerSequence: 1238396, | ||
SigningPubKey: | ||
'027497533006d024ffb612a2110eb327ccfeed2b752d787c96ab2d3cca425a40e8', | ||
}, | ||
txnHex: | ||
'53545800120000220000000024000A5342201B0012E57C6140000000004C4B4068400000000000000C7321027497533006D024FFB612A2110EB327CCFEED2B752D787C96AB2D3CCA425A40E88114FF2BC637244009494C6203505254126638AAD7CD8314A0F766DFCC0B5DDC91E7679C7539590983A41D9F', | ||
}, | ||
}, | ||
queries: [ | ||
{ | ||
name: 'Initate query', | ||
data: queryToUint8Array({ | ||
signTxn: { | ||
initiate: { | ||
walletId: new Uint8Array([ | ||
199, 89, 252, 26, 32, 135, 183, 211, 90, 220, 38, 17, 160, 103, | ||
233, 62, 110, 172, 92, 20, 35, 250, 190, 146, 62, 8, 53, 86, 128, | ||
26, 3, 187, 121, 64, | ||
]), | ||
derivationPath: [ | ||
0x80000000 + 44, | ||
0x80000000 + 144, | ||
0x80000000, | ||
0, | ||
0, | ||
], | ||
transactionSize: 120, | ||
}, | ||
}, | ||
}), | ||
}, | ||
], | ||
}; | ||
|
||
const withUnknownError: ISignTxnTestCase = { | ||
name: 'With unknown error', | ||
...commonParams, | ||
results: [ | ||
{ | ||
name: 'error', | ||
data: resultToUint8Array({ | ||
signTxn: { | ||
commonError: { | ||
unknownError: 1, | ||
}, | ||
}, | ||
}), | ||
}, | ||
], | ||
errorInstance: DeviceAppError, | ||
errorMessage: | ||
deviceAppErrorTypeDetails[DeviceAppErrorType.UNKNOWN_ERROR].message, | ||
}; | ||
|
||
const withInvalidResult: ISignTxnTestCase = { | ||
name: 'With invalid result', | ||
...commonParams, | ||
results: [ | ||
{ | ||
name: 'error', | ||
data: new Uint8Array([18, 4, 26, 2, 24, 1]), | ||
}, | ||
], | ||
errorInstance: DeviceAppError, | ||
errorMessage: | ||
deviceAppErrorTypeDetails[DeviceAppErrorType.INVALID_MSG_FROM_DEVICE] | ||
.message, | ||
}; | ||
|
||
const error: ISignTxnTestCase[] = [withUnknownError, withInvalidResult]; | ||
|
||
export default error; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
import { IFixtures } from './types'; | ||
import error from './error'; | ||
import invalidData from './invalidData'; | ||
import invalidArgs from './invalidArgs'; | ||
import valid from './valid'; | ||
|
||
const fixtures: IFixtures = { | ||
valid, | ||
invalidArgs, | ||
error, | ||
invalidData, | ||
}; | ||
|
||
export default fixtures; |
Oops, something went wrong.