Skip to content

Commit de91cb3

Browse files
authored
Merge pull request #267 from radixdlt/subintent-builder
feat(rdt): add subintent request builder
2 parents 4ccd67c + c43fdbb commit de91cb3

File tree

8 files changed

+176
-29
lines changed

8 files changed

+176
-29
lines changed

examples/simple-dapp/src/main.ts

+7-9
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {
88
OneTimeDataRequestBuilder,
99
LocalStorageModule,
1010
generateRolaChallenge,
11+
SubintentRequestBuilder,
1112
} from '@radixdlt/radix-dapp-toolkit'
1213

1314
const dAppDefinitionAddress = import.meta.env.VITE_DAPP_DEFINITION_ADDRESS
@@ -85,16 +86,13 @@ removeCb.onclick = () => {
8586

8687
subintentButton.onclick = async () => {
8788
console.log(subintentManifest.value)
88-
const result = await dAppToolkit.walletApi.sendPreAuthorizationRequest({
89-
transactionManifest: subintentManifest.value,
90-
childSubintentHashes: [],
91-
expiration: {
92-
discriminator: 'expireAfterSignature',
93-
value: 3600,
94-
},
95-
})
89+
const result = await dAppToolkit.walletApi.sendPreAuthorizationRequest(
90+
SubintentRequestBuilder()
91+
.manifest(subintentManifest.value)
92+
.setExpiration('secondsAfterSignature', 3600),
93+
)
9694

97-
console.log(result);
95+
console.log(result)
9896
}
9997

10098
addCb.onclick = () => {

packages/dapp-toolkit/src/_types.ts

+2-8
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import type {
2626
WalletRequestModule,
2727
ConnectButtonModule,
2828
} from './modules'
29+
import { BuildableSubintentRequest } from './modules/wallet-request/pre-authorization-request/subintent-builder'
2930

3031
export type Providers = {
3132
connectButtonModule: ConnectButtonModule
@@ -100,14 +101,7 @@ export type SendTransactionInput = {
100101
onTransactionId?: (transactionId: string) => void
101102
}
102103

103-
export type SendPreAuthorizationRequestInput = {
104-
transactionManifest: string
105-
version?: number
106-
blobs?: string[]
107-
message?: string
108-
childSubintentHashes: string[]
109-
expiration: ExpireAtTime | ExpireAfterSignature
110-
}
104+
export type SendPreAuthorizationRequestInput = BuildableSubintentRequest
111105

112106
export type ButtonApi = {
113107
setMode: (value: 'light' | 'dark') => void

packages/dapp-toolkit/src/modules/wallet-request/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,4 @@ export * from './session/session.module'
66
export * from './transport'
77
export * from './wallet-request-sdk'
88
export * from './wallet-request'
9+
export * from './pre-authorization-request'
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from './subintent-builder'
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
import { describe, expect, it } from 'vitest'
2+
import { SubintentRequestBuilder } from './subintent-builder'
3+
4+
describe('SubintentRequestBuilder', () => {
5+
it('should build a subintent request', () => {
6+
const tx = SubintentRequestBuilder()
7+
.manifest('...')
8+
.setExpiration('secondsAfterSignature', 60)
9+
.addBlobs('deadbeef', 'beefdead')
10+
.message('hello')
11+
.toRequestItem()
12+
13+
expect(tx).toEqual({
14+
discriminator: 'subintent',
15+
version: 1,
16+
transactionManifestVersion: 1,
17+
transactionManifest: '...',
18+
expiration: {
19+
discriminator: 'expireAfterSignature',
20+
value: 60,
21+
},
22+
blobs: ['deadbeef', 'beefdead'],
23+
message: 'hello',
24+
})
25+
})
26+
27+
it('should build a subintent request using raw object', () => {
28+
const tx = SubintentRequestBuilder()
29+
.rawConfig({
30+
version: 1,
31+
transactionManifestVersion: 1,
32+
transactionManifest: '...',
33+
expiration: {
34+
discriminator: 'expireAfterSignature',
35+
value: 60,
36+
},
37+
blobs: ['deadbeef', 'beefdead'],
38+
message: 'hello',
39+
})
40+
.toRequestItem()
41+
42+
expect(tx).toEqual({
43+
discriminator: 'subintent',
44+
version: 1,
45+
transactionManifestVersion: 1,
46+
transactionManifest: '...',
47+
expiration: {
48+
discriminator: 'expireAfterSignature',
49+
value: 60,
50+
},
51+
blobs: ['deadbeef', 'beefdead'],
52+
message: 'hello',
53+
})
54+
})
55+
})
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
import { SubintentRequestItem } from '../../../schemas'
2+
3+
export type BuildableSubintentRequest = {
4+
toRequestItem: () => SubintentRequestItem
5+
}
6+
/**
7+
* A builder function for creating a SubintentRequest.
8+
*
9+
* @returns An object with methods to configure and build a SubintentRequestItem.
10+
*
11+
* @example
12+
* const builder = SubintentRequestBuilder();
13+
* const requestItem = builder
14+
* .manifest('some-manifest')
15+
* .setExpiration('atTime', 1234567890)
16+
* .addBlobs('blob1', 'blob2')
17+
* .message('This is a message')
18+
19+
*/
20+
export const SubintentRequestBuilder = () => {
21+
let state: Partial<SubintentRequestItem> = {
22+
discriminator: 'subintent',
23+
version: 1,
24+
transactionManifestVersion: 1,
25+
}
26+
27+
/**
28+
* Sets the expiration for a request.
29+
*
30+
* @param type - The type of expiration. Can be 'atTime' for a specific time or 'secondsAfterSignature' for a duration after the signature.
31+
* @param value - The value associated with the expiration type. For 'atTime', this is a timestamp. For 'secondsAfterSignature', this is the number of seconds.
32+
* @returns The API object for chaining.
33+
*/
34+
const setExpiration = (
35+
type: 'atTime' | 'secondsAfterSignature',
36+
value: number,
37+
) => {
38+
state.expiration = {
39+
discriminator:
40+
type === 'atTime' ? 'expireAtTime' : 'expireAfterSignature',
41+
value,
42+
}
43+
return api
44+
}
45+
46+
/**
47+
* Adds the provided blobs to the state.
48+
*
49+
* @param blobs - A list of blob strings to be added to the state.
50+
* @returns The API object for chaining.
51+
*/
52+
const addBlobs = (...blobs: string[]) => {
53+
state.blobs = blobs
54+
return api
55+
}
56+
57+
/**
58+
* Sets the message to be included in the subintent transaction.
59+
*
60+
* @param message - The message to be set in the state.
61+
* @returns The API object for chaining further calls.
62+
*/
63+
const message = (message: string) => {
64+
state.message = message
65+
return api
66+
}
67+
68+
/**
69+
* Sets the transaction manifest in the state and returns the API object.
70+
*
71+
* @param value - The transaction manifest to be set.
72+
* @returns The API object for method chaining.
73+
*/
74+
const manifest = (value: string) => {
75+
state.transactionManifest = value
76+
return api
77+
}
78+
79+
/**
80+
* Converts the current state to a SubintentRequestItem.
81+
*
82+
* @returns {SubintentRequestItem} The current state cast as a SubintentRequestItem.
83+
*/
84+
const toRequestItem = () => state as SubintentRequestItem
85+
86+
/**
87+
* Sets the raw configuration for the builder.
88+
*
89+
* @param rawConfig - The raw configuration to set.
90+
* @returns The API object for method chaining.
91+
*/
92+
const rawConfig = (
93+
rawConfig: Omit<SubintentRequestItem, 'discriminator'>,
94+
) => {
95+
state = { ...rawConfig, discriminator: 'subintent' }
96+
return { toRequestItem }
97+
}
98+
99+
const api = {
100+
setExpiration,
101+
addBlobs,
102+
message,
103+
toRequestItem,
104+
} as const
105+
106+
return { manifest, rawConfig }
107+
}

packages/dapp-toolkit/src/modules/wallet-request/wallet-request.ts

+2-11
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,7 @@ import {
1111
import { validateRolaChallenge, type Logger } from '../../helpers'
1212
import { TransactionStatus } from '../gateway'
1313
import { ResultAsync, err, ok, okAsync } from 'neverthrow'
14-
import type {
15-
MessageLifeCycleEvent,
16-
WalletInteraction,
17-
} from '../../schemas'
14+
import type { MessageLifeCycleEvent, WalletInteraction } from '../../schemas'
1815
import { SdkError } from '../../error'
1916
import {
2017
DataRequestBuilderItem,
@@ -310,13 +307,7 @@ export const WalletRequestModule = (input: {
310307
> => {
311308
const walletInteraction = walletRequestSdk.createWalletInteraction({
312309
discriminator: 'preAuthorizationRequest',
313-
subintent: {
314-
discriminator: 'subintent',
315-
blobs: value.blobs,
316-
transactionManifest: value.transactionManifest,
317-
message: value.message,
318-
version: value.version ?? 1,
319-
},
310+
subintent: value.toRequestItem(),
320311
})
321312

322313
return addNewRequest('preAuthorizationRequest', walletInteraction, false)

packages/dapp-toolkit/src/schemas/index.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -260,10 +260,10 @@ export type SubintentRequestItem = InferOutput<typeof SubintentRequestItem>
260260
export const SubintentRequestItem = object({
261261
discriminator: literal('subintent'),
262262
version: number(),
263+
transactionManifestVersion: number(),
263264
transactionManifest: string(),
264265
blobs: optional(array(string())),
265266
message: optional(string()),
266-
childSubintentHashes: optional(array(string())),
267267
expiration: optional(union([ExpireAtTime, ExpireAfterSignature])),
268268
})
269269

0 commit comments

Comments
 (0)