Skip to content

Commit

Permalink
Merge pull request #15 from argentlabs/fix/sign-typed-data
Browse files Browse the repository at this point in the history
fix: sign typed data
  • Loading branch information
bluecco authored May 31, 2024
2 parents 3938f46 + 13e3f5f commit 334273e
Show file tree
Hide file tree
Showing 6 changed files with 221 additions and 45 deletions.
43 changes: 43 additions & 0 deletions src/__tests__/fixture.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
export const outsideExecutionTypedDataFixture = (to: string) => ({
types: {
StarknetDomain: [
{ name: "name", type: "shortstring" },
{ name: "version", type: "shortstring" },
{ name: "chainId", type: "shortstring" },
{ name: "revision", type: "shortstring" },
],
OutsideExecution: [
{ name: "Caller", type: "ContractAddress" },
{ name: "Nonce", type: "felt" },
{ name: "Execute After", type: "u128" },
{ name: "Execute Before", type: "u128" },
{ name: "Calls", type: "Call*" },
],
Call: [
{ name: "To", type: "ContractAddress" },
{ name: "Selector", type: "selector" },
{ name: "Calldata", type: "felt*" },
],
},
primaryType: "OutsideExecution",
domain: {
name: "Account.execute_from_outside",
version: "1",
chainId: "0x534e5f474f45524c49",
revision: "1",
},
message: {
Caller: "0x414e595f43414c4c4552",
"Execute After": 1,
"Execute Before": 999999999999999,
Nonce: "0x1",
Calls: [
{
Selector:
"0x2f043e3dd744a94c4afd9d35321851d44c14a01fa5b2b8a05e054b12e5cc838",
To: to,
Calldata: ["0x123"],
},
],
},
})
22 changes: 12 additions & 10 deletions src/__tests__/sessionBackendService.test.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
import { OutsideExecution } from "@/outsideExecution"
import { HttpResponse, http } from "msw"
import { setupServer } from "msw/node"
import { constants, stark } from "starknet"
import { StarknetChainId } from "starknet-types"
import { afterAll, afterEach, beforeAll, describe, expect, it } from "vitest"
import {
OutsideExecution,
getOutsideExecutionTypedData,
} from "../outsideExecution"
import { ArgentBackendSessionService } from "../sessionBackendService"
import { BackendSignatureResponse } from "../sessionTypes"
import { getSessionTypedData } from "../utils"
Expand Down Expand Up @@ -152,15 +155,14 @@ describe("ArgentBackendSessionService", () => {

const chainId: StarknetChainId = constants.StarknetChainId.SN_SEPOLIA

const response: BackendSignatureResponse =
await service.signOutsideTxAndSession(
sessionTokenToSign,
accountAddress,
outsideExecution,
[123n, 456n],
false,
chainId,
)
const response: BackendSignatureResponse = await service.signSessionEFO(
sessionTokenToSign,
accountAddress,
getOutsideExecutionTypedData(outsideExecution, chainId),
[123n, 456n],
false,
chainId,
)

expect(response).toStrictEqual({
publicKey: "0x123",
Expand Down
57 changes: 49 additions & 8 deletions src/__tests__/sessionDappService.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { StarknetChainId } from "starknet-types"
import { beforeAll, describe, expect, it, vi } from "vitest"
import { ArgentBackendSessionService } from "../sessionBackendService"
import { SessionDappService } from "../sessionDappService"
import { outsideExecutionTypedDataFixture } from "./fixture"

const allowedMethodContractAddress = stark.randomAddress()

Expand Down Expand Up @@ -107,7 +108,7 @@ describe("SessionDappService", () => {
})
})

it("should get an outside execution call with execute_from_outside_v2", async () => {
it("should get an outside execution call with getOutsideExecutionCall", async () => {
const provider = new RpcProvider()
vi.spyOn(provider, "getChainId").mockImplementation(
async () => StarknetChainId.SN_SEPOLIA,
Expand All @@ -124,13 +125,11 @@ describe("SessionDappService", () => {
},
]

vi.spyOn(argentBackend, "signOutsideTxAndSession").mockImplementation(
async () => ({
publicKey: "0x123",
r: 10n,
s: 10n,
}),
)
vi.spyOn(argentBackend, "signSessionEFO").mockImplementation(async () => ({
publicKey: "0x123",
r: 10n,
s: 10n,
}))

const outsideExecutionCall =
await sessionDappService.getOutsideExecutionCall(
Expand All @@ -150,4 +149,46 @@ describe("SessionDappService", () => {
expect(outsideExecutionCall.calldata).toBeInstanceOf(Array)
expect(outsideExecutionCall.calldata).not.toBe([])
})

it("should get an outside execution call with getOutsideExecutionTypedData", async () => {
const provider = new RpcProvider()
vi.spyOn(provider, "getChainId").mockImplementation(
async () => StarknetChainId.SN_SEPOLIA,
)
const address = stark.randomAddress()
const execute_after = 1
const execute_before = 999999999999999
const nonce = "0x1"
const calls: Call[] = [
{
contractAddress: allowedMethodContractAddress,
entrypoint: "some_method",
calldata: ["0x123"],
},
]

vi.spyOn(argentBackend, "signSessionEFO").mockImplementation(async () => ({
publicKey: "0x123",
r: 10n,
s: 10n,
}))

const { signature, outsideExecutionTypedData } =
await sessionDappService.getOutsideExecutionTypedData(
sessionRequest,
sessionAuthorizationSignature,
false,
calls,
address,
"",
execute_after,
execute_before,
nonce,
)

expect(signature).toBeInstanceOf(Array)
expect(outsideExecutionTypedData).toStrictEqual(
outsideExecutionTypedDataFixture(allowedMethodContractAddress),
)
})
})
21 changes: 17 additions & 4 deletions src/outsideExecution.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import {
ArraySignatureType,
Call,
CallData,
RawArgs,
Expand All @@ -9,7 +10,7 @@ import {
type Provider,
type ProviderInterface,
} from "starknet"
import { StarknetChainId } from "starknet-types"
import { StarknetChainId, TypedData } from "starknet-types"

export const typesRev1 = {
StarknetDomain: [
Expand Down Expand Up @@ -71,12 +72,12 @@ export function getTypedDataHash(
chainId: string,
): string {
return typedData.getMessageHash(
getTypedData(outsideExecution, chainId),
getOutsideExecutionTypedData(outsideExecution, chainId),
accountAddress,
)
}

export function getTypedData(
export function getOutsideExecutionTypedData(
outsideExecution: OutsideExecution,
chainId: string,
) {
Expand Down Expand Up @@ -108,11 +109,23 @@ export async function getOutsideExecutionCall(
chainId?: StarknetChainId,
): Promise<Call> {
chainId = chainId ?? (await provider.getChainId())
const currentTypedData = getTypedData(outsideExecution, chainId)
const currentTypedData = getOutsideExecutionTypedData(
outsideExecution,
chainId,
)
const signature = await signer.signMessage(currentTypedData, accountAddress)
return {
contractAddress: accountAddress,
entrypoint: "execute_from_outside_v2",
calldata: CallData.compile({ ...outsideExecution, signature }),
}
}

export type OutsideExecutionTypedData = ReturnType<
typeof getOutsideExecutionTypedData
>

export type OutsideExecutionTypedDataResponse = {
signature: ArraySignatureType
outsideExecutionTypedData: TypedData
}
6 changes: 2 additions & 4 deletions src/sessionBackendService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import {
import { StarknetChainId, TypedData } from "starknet-types"
import { ARGENT_BACKEND_BASE_URL } from "./constants"
import { SignSessionError } from "./errors"
import { OutsideExecution, getTypedData } from "./outsideExecution"
import {
BackendSessionBody,
BackendSignSessionBody,
Expand Down Expand Up @@ -139,10 +138,10 @@ export class ArgentBackendSessionService {
return json.signature
}

public async signOutsideTxAndSession(
public async signSessionEFO(
sessionTokenToSign: OffChainSession,
accountAddress: string,
outsideExecution: OutsideExecution,
currentTypedData: TypedData,
sessionSignature: bigint[],
cacheAuthorisation: boolean,
chainId: StarknetChainId,
Expand All @@ -151,7 +150,6 @@ export class ArgentBackendSessionService {
getSessionTypedData(sessionTokenToSign, chainId),
accountAddress,
)
const currentTypedData = getTypedData(outsideExecution, chainId)

const sessionAuthorisation = stark.formatSignature(
this.accountSessionSignature,
Expand Down
Loading

0 comments on commit 334273e

Please sign in to comment.