Skip to content

Commit 05b5045

Browse files
authored
✨ (signer-aleo) [LIVE-30136]: Add support for signing nested calls (#1478)
2 parents 531ed9f + aed59a5 commit 05b5045

17 files changed

Lines changed: 625 additions & 4 deletions

File tree

.changeset/crazy-pigs-rhyme.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@ledgerhq/device-signer-kit-aleo": minor
3+
---
4+
5+
Add support for signing nested calls

apps/sample/src/components/SignerAleoView/index.tsx

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ import {
1212
type SignFeeIntentDAError,
1313
type SignFeeIntentDAIntermediateValue,
1414
type SignFeeIntentDAOutput,
15+
type SignNestedCallDAError,
16+
type SignNestedCallDAIntermediateValue,
17+
type SignNestedCallDAOutput,
1518
type SignRootIntentDAError,
1619
type SignRootIntentDAIntermediateValue,
1720
type SignRootIntentDAOutput,
@@ -69,7 +72,7 @@ export const SignerAleoView: React.FC<{ sessionId: string }> = ({
6972
});
7073
},
7174
initialValues: {
72-
derivationPath: "44'/683'/0",
75+
derivationPath: "44'/683'/0'/0'",
7376
checkOnDevice: false,
7477
skipOpenApp: false,
7578
},
@@ -134,7 +137,7 @@ export const SignerAleoView: React.FC<{ sessionId: string }> = ({
134137
});
135138
},
136139
initialValues: {
137-
derivationPath: "44'/683'/0",
140+
derivationPath: "44'/683'/0'/0'",
138141
rootIntent: "",
139142
skipOpenApp: false,
140143
},
@@ -186,6 +189,44 @@ export const SignerAleoView: React.FC<{ sessionId: string }> = ({
186189
SignFeeIntentDAError,
187190
SignFeeIntentDAIntermediateValue
188191
>,
192+
{
193+
title: "Sign Nested Call",
194+
description: "Sign a nested call with the device",
195+
executeDeviceAction: ({ nestedCallRequest, skipOpenApp }) => {
196+
if (!signer) {
197+
throw new Error("Signer not initialized");
198+
}
199+
// Convert hex string to Uint8Array
200+
const nestedCallRequestBytes = nestedCallRequest.startsWith("0x")
201+
? new Uint8Array(
202+
nestedCallRequest
203+
.slice(2)
204+
.match(/.{1,2}/g)
205+
?.map((byte) => Number.parseInt(byte, 16)) ?? [],
206+
)
207+
: new Uint8Array(
208+
nestedCallRequest
209+
.match(/.{1,2}/g)
210+
?.map((byte) => Number.parseInt(byte, 16)) ?? [],
211+
);
212+
return signer.signNestedCall(nestedCallRequestBytes, {
213+
skipOpenApp,
214+
});
215+
},
216+
initialValues: {
217+
nestedCallRequest: "",
218+
skipOpenApp: false,
219+
},
220+
deviceModelId,
221+
} satisfies DeviceActionProps<
222+
SignNestedCallDAOutput,
223+
{
224+
nestedCallRequest: string;
225+
skipOpenApp?: boolean;
226+
},
227+
SignNestedCallDAError,
228+
SignNestedCallDAIntermediateValue
229+
>,
189230
],
190231
[deviceModelId, signer],
191232
);

packages/signer/signer-aleo/src/api/SignerAleo.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { type GetAddressDAReturnType } from "@api/app-binder/GetAddressDeviceAct
22
import { type GetAppConfigDAReturnType } from "@api/app-binder/GetAppConfigDeviceActionTypes";
33
import { type GetViewKeyDAReturnType } from "@api/app-binder/GetViewKeyDeviceActionTypes";
44
import { type SignFeeIntentDAReturnType } from "@api/app-binder/SignFeeIntentDeviceActionTypes";
5+
import { type SignNestedCallDAReturnType } from "@api/app-binder/SignNestedCallDeviceActionTypes";
56
import { type SignRootIntentDAReturnType } from "@api/app-binder/SignRootIntentDeviceActionTypes";
67
import { type AddressOptions } from "@api/model/AddressOptions";
78
import { type TransactionOptions } from "@api/model/TransactionOptions";
@@ -25,6 +26,11 @@ export interface SignerAleo {
2526
options?: TransactionOptions,
2627
) => SignRootIntentDAReturnType;
2728

29+
signNestedCall: (
30+
nestedCallRequest: Uint8Array,
31+
options?: TransactionOptions,
32+
) => SignNestedCallDAReturnType;
33+
2834
signFeeIntent: (
2935
feeIntent: Uint8Array,
3036
options?: TransactionOptions,
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import {
2+
type CommandErrorResult,
3+
type ExecuteDeviceActionReturnType,
4+
type OpenAppDAError,
5+
type OpenAppDARequiredInteraction,
6+
type UserInteractionRequired,
7+
} from "@ledgerhq/device-management-kit";
8+
9+
import { type SignNestedCallCommandResponse } from "@internal/app-binder/command/SignNestedCallCommand";
10+
import { type AleoErrorCodes } from "@internal/app-binder/command/utils/aleoApplicationErrors";
11+
12+
export type SignNestedCallDAOutput = SignNestedCallCommandResponse;
13+
14+
export type SignNestedCallDAError =
15+
| OpenAppDAError
16+
| CommandErrorResult<AleoErrorCodes>["error"];
17+
18+
type SignNestedCallDARequiredInteraction =
19+
| OpenAppDARequiredInteraction
20+
| UserInteractionRequired.None;
21+
22+
export type SignNestedCallDAIntermediateValue = {
23+
requiredUserInteraction: SignNestedCallDARequiredInteraction;
24+
};
25+
26+
export type SignNestedCallDAReturnType = ExecuteDeviceActionReturnType<
27+
SignNestedCallDAOutput,
28+
SignNestedCallDAError,
29+
SignNestedCallDAIntermediateValue
30+
>;

packages/signer/signer-aleo/src/api/index.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,11 @@ export type {
1818
SignFeeIntentDAIntermediateValue,
1919
SignFeeIntentDAOutput,
2020
} from "@api/app-binder/SignFeeIntentDeviceActionTypes";
21+
export type {
22+
SignNestedCallDAError,
23+
SignNestedCallDAIntermediateValue,
24+
SignNestedCallDAOutput,
25+
} from "@api/app-binder/SignNestedCallDeviceActionTypes";
2126
export type {
2227
SignRootIntentDAError,
2328
SignRootIntentDAIntermediateValue,

packages/signer/signer-aleo/src/internal/DefaultSignerAleo.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { type GetAddressDAReturnType } from "@api/app-binder/GetAddressDeviceAct
88
import { type GetAppConfigDAReturnType } from "@api/app-binder/GetAppConfigDeviceActionTypes";
99
import { type GetViewKeyDAReturnType } from "@api/app-binder/GetViewKeyDeviceActionTypes";
1010
import { type SignFeeIntentDAReturnType } from "@api/app-binder/SignFeeIntentDeviceActionTypes";
11+
import { type SignNestedCallDAReturnType } from "@api/app-binder/SignNestedCallDeviceActionTypes";
1112
import { type SignRootIntentDAReturnType } from "@api/app-binder/SignRootIntentDeviceActionTypes";
1213
import { type AddressOptions } from "@api/model/AddressOptions";
1314
import { type TransactionOptions } from "@api/model/TransactionOptions";
@@ -20,6 +21,7 @@ import { configTypes } from "@internal/use-cases/config/di/configTypes";
2021
import { type GetAppConfigUseCase } from "@internal/use-cases/config/GetAppConfigUseCase";
2122
import { transactionTypes } from "@internal/use-cases/transaction/di/transactionTypes";
2223
import { type SignFeeIntentUseCase } from "@internal/use-cases/transaction/SignFeeIntentUseCase";
24+
import { type SignNestedCallUseCase } from "@internal/use-cases/transaction/SignNestedCallUseCase";
2325
import { type SignRootIntentUseCase } from "@internal/use-cases/transaction/SignRootIntentUseCase";
2426

2527
type DefaultSignerAleoConstructorArgs = {
@@ -68,6 +70,15 @@ export class DefaultSignerAleo implements SignerAleo {
6870
.execute(derivationPath, rootIntent, options);
6971
}
7072

73+
signNestedCall(
74+
nestedCallRequest: Uint8Array,
75+
options?: TransactionOptions,
76+
): SignNestedCallDAReturnType {
77+
return this._container
78+
.get<SignNestedCallUseCase>(transactionTypes.SignNestedCallUseCase)
79+
.execute(nestedCallRequest, options);
80+
}
81+
7182
signFeeIntent(
7283
feeIntent: Uint8Array,
7384
options?: TransactionOptions,

packages/signer/signer-aleo/src/internal/app-binder/AleoAppBinder.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import { type GetAddressDAReturnType } from "@api/app-binder/GetAddressDeviceAct
1111
import { type GetAppConfigDAReturnType } from "@api/app-binder/GetAppConfigDeviceActionTypes";
1212
import { type GetViewKeyDAReturnType } from "@api/app-binder/GetViewKeyDeviceActionTypes";
1313
import { type SignFeeIntentDAReturnType } from "@api/app-binder/SignFeeIntentDeviceActionTypes";
14+
import { type SignNestedCallDAReturnType } from "@api/app-binder/SignNestedCallDeviceActionTypes";
1415
import { type SignRootIntentDAReturnType } from "@api/app-binder/SignRootIntentDeviceActionTypes";
1516
import { APP_NAME } from "@internal/app-binder/constants";
1617
import { externalTypes } from "@internal/externalTypes";
@@ -19,6 +20,7 @@ import { GetAddressCommand } from "./command/GetAddressCommand";
1920
import { GetAppConfigCommand } from "./command/GetAppConfigCommand";
2021
import { GetViewKeyCommand } from "./command/GetViewKeyCommand";
2122
import { SignFeeIntentTask } from "./task/SignFeeIntentTask";
23+
import { SignNestedCallTask } from "./task/SignNestedCallTask";
2224
import { SignRootIntentTask } from "./task/SignRootIntentTask";
2325

2426
@injectable()
@@ -101,6 +103,26 @@ export class AleoAppBinder {
101103
});
102104
}
103105

106+
signNestedCall(args: {
107+
nestedCallRequest: Uint8Array;
108+
skipOpenApp: boolean;
109+
}): SignNestedCallDAReturnType {
110+
return this.dmk.executeDeviceAction({
111+
sessionId: this.sessionId,
112+
deviceAction: new CallTaskInAppDeviceAction({
113+
input: {
114+
task: (internalApi) =>
115+
new SignNestedCallTask(internalApi, {
116+
nestedCallRequest: args.nestedCallRequest,
117+
}).run(),
118+
appName: APP_NAME,
119+
requiredUserInteraction: UserInteractionRequired.None,
120+
skipOpenApp: args.skipOpenApp,
121+
},
122+
}),
123+
});
124+
}
125+
104126
signFeeIntent(args: {
105127
feeIntent: Uint8Array;
106128
skipOpenApp: boolean;

0 commit comments

Comments
 (0)