Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: decouple from snjs #194

Merged
merged 17 commits into from
Feb 15, 2024
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 0 additions & 10 deletions packages/core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,19 +32,9 @@
"devDependencies": {
"c8": "^7.12.0",
"happy-dom": "^6.0.4",
"starknet": "^5.18.0",
"starknet4": "npm:[email protected]",
"typescript": "^4.6.4",
"vite": "^3.0.0",
"vite-plugin-dts": "^1.4.0",
"vitest": "^0.19.1"
},
"peerDependencies": {
"starknet": "^5.18.0"
},
"peerDependenciesMeta": {
"starknet": {
"optional": false
}
}
}
259 changes: 214 additions & 45 deletions packages/core/src/StarknetWindowObject.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,69 @@
import type { AccountInterface, ProviderInterface } from "starknet"
import type {
AccountInterface as AccountInterfaceV4,
ProviderInterface as ProviderInterfaceV4,
} from "starknet4"
export enum StarknetChainId {
SN_MAIN = "0x534e5f4d41494e",
SN_GOERLI = "0x534e5f474f45524c49",
}
Copy link

@PhilippeR26 PhilippeR26 Dec 22, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should add Sepolia Testnet, as Braavos is handling it.

SN_SEPOLIA = "0x534e5f5345504f4c4941"


export enum Permission {
Accounts = "accounts",
}

type FELT = string

type Call = {
contract_address: FELT
avimak marked this conversation as resolved.
Show resolved Hide resolved

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Call type : This type name already exists in Starknet.js, but their definition are not the same, generating confusion when coding. My proposal is to rename in the interface Call to CallParameters.

entrypoint: string
calldata?: FELT[]
}

type SIERRA_ENTRY_POINT = {
selector: FELT
function_idx: number
}

type StarknetMerkleType = {
name: string
type: "merkletree"
contains: string
}

/**
* A single type, as part of a struct. The `type` field can be any of the EIP-712 supported types.
*
* Note that the `uint` and `int` aliases like in Solidity, and fixed point numbers are not supported by the EIP-712
* standard.
*/
type StarknetType =
| {
name: string
type: string
}
| StarknetMerkleType

/**
* The EIP712 domain struct. Any of these fields are optional, but it must contain at least one field.
*/
interface StarknetDomain extends Record<string, unknown> {
name?: string
version?: string
chainId?: string | number
}

export type AccountChangeEventHandler = (accounts: string[]) => void
/**
dhruvkelawala marked this conversation as resolved.
Show resolved Hide resolved
* The complete typed data, with all the structs, domain data, primary type of the message, and the message itself.
*/
export interface TypedData {
types: Record<string, StarknetType[]>
primaryType: string
domain: StarknetDomain
message: Record<string, unknown>
}

export type NetworkChangeEventHandler = (network?: string) => void
export type AccountChangeEventHandler = (accounts?: string[]) => void

export type NetworkChangeEventHandler = (
chainId?: StarknetChainId,
accounts?: string[],
) => void

export type WalletEvents =
| {
Expand All @@ -18,44 +75,157 @@ export type WalletEvents =
handler: NetworkChangeEventHandler
}

// EIP-747:
// https://github.com/ethereum/EIPs/blob/master/EIPS/eip-747.md
/**
* INVOKE_TXN_V1
* @see https://github.com/starkware-libs/starknet-specs/blob/master/api/starknet_api_openrpc.json
*/
export interface AddInvokeTransactionParameters {
/**
* Calls to invoke by the account
*/
calls: Call[]
}
export interface AddInvokeTransactionResult {
/**
* The hash of the invoke transaction
*/
transaction_hash: FELT
}

/**
* BROADCASTED_DECLARE_TXN_V2
* @see https://github.com/starkware-libs/starknet-specs/blob/master/api/starknet_api_openrpc.json
*/
export interface AddDeclareTransactionParameters {
/**
* The hash of the Cairo assembly resulting from the Sierra compilation
*/
compiled_class_hash: FELT
contract_class: {
/**
* The list of Sierra instructions of which the program consists
*/
sierra_program: FELT[]
/**
* The version of the contract class object. Currently, the Starknet OS supports version 0.1.0
*/
contract_class_version: string
/**
* Entry points by type
*/
entry_points_by_type: {
CONSTRUCTOR: SIERRA_ENTRY_POINT[]
EXTERNAL: SIERRA_ENTRY_POINT[]
L1_HANDLER: SIERRA_ENTRY_POINT[]
}
/**
* The class ABI, as supplied by the user declaring the class
*/
abi?: string
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Type string for abi is not working properly.
Only any[] is working properly.

}
export interface AddDeclareTransactionResult {
/**
* The hash of the declare transaction
*/
transaction_hash: FELT
/**
* The hash of the declared class
*/
class_hash: FELT
}

/**
* DEPLOY_ACCOUNT_TXN_V1
* @see https://github.com/starkware-libs/starknet-specs/blob/master/api/starknet_api_openrpc.json
*/
export interface AddDeployAccountTransactionParameters {
/**
* The salt for the address of the deployed contract
*/
contract_address_salt: FELT
/**
* The parameters passed to the constructor
*/
constructor_calldata: FELT[]
/**
* The hash of the deployed contract's class
*/
class_hash: FELT
}
export interface AddDeployAccountTransactionResult {
/**
* The hash of the deploy transaction
*/
transaction_hash: FELT
/**
* The address of the new contract
*/
contract_address: FELT
}

/**
* EIP-1102:
* @see https://eips.ethereum.org/EIPS/eip-1102
*/
export interface RequestAccountsParameters {
/**
* If true, the wallet will not show the wallet-unlock UI in case of a locked wallet,
* nor the dApp-approve UI in case of a non-allowed dApp.
*/
silentMode?: boolean
}

/**
* EIP-747:
* @see https://github.com/ethereum/EIPs/blob/master/EIPS/eip-747.md
*/
export interface WatchAssetParameters {
type: "ERC20" // The asset's interface, e.g. 'ERC20'
options: {
address: string // The hexadecimal StarkNet address of the token contract
address: string // The hexadecimal Starknet address of the token contract
symbol?: string // A ticker symbol or shorthand, up to 5 alphanumerical characters
decimals?: number // The number of asset decimals
image?: string // A string url of the token logo
name?: string // The name of the token - not in spec
}
}

// EIP-3085
// https://github.com/ethereum/EIPs/blob/master/EIPS/eip-3085.md

/**
* EIP-3085:
* @see https://github.com/ethereum/EIPs/blob/master/EIPS/eip-3085.md
*/
export interface AddStarknetChainParameters {
id: string
chainId: string // A 0x-prefixed hexadecimal string
chainName: string
baseUrl: string
rpcUrls?: string[]
blockExplorerUrls?: string[]

nativeCurrency?: {
address: string // Not part of the standard, but required by StarkNet as it can work with any ERC20 token as the fee token
address: string // Not part of the standard, but required by Starknet as it can work with any ERC20 token as the fee token
name: string
symbol: string // 2-6 characters long
decimals: number
} // Currently ignored.
iconUrls?: string[] // Currently ignored.
}

export interface SwitchStarknetChainParameter {
export interface SwitchStarknetChainParameters {
chainId: string // A 0x-prefixed hexadecimal string
}

export type RpcMessage =
| {
type: "wallet_getPermissions"
params: never
result: Permission[]
}
| {
avimak marked this conversation as resolved.
Show resolved Hide resolved
type: "wallet_requestAccounts"
params?: RequestAccountsParameters
result: string[]
}
| {
type: "wallet_watchAsset"
params: WatchAssetParameters
Expand All @@ -68,20 +238,43 @@ export type RpcMessage =
}
| {
type: "wallet_switchStarknetChain"
params: SwitchStarknetChainParameter
params: SwitchStarknetChainParameters
result: boolean
}
| {
type: "wallet_requestChainId"
params: never
result: StarknetChainId // returns the chain ID of the current network
}
| {
avimak marked this conversation as resolved.
Show resolved Hide resolved
type: "starknet_addInvokeTransaction"
params: AddInvokeTransactionParameters
result: AddInvokeTransactionResult
}
| {
type: "starknet_addDeclareTransaction"
params: AddDeclareTransactionParameters
result: AddDeclareTransactionResult
}
| {
type: "starknet_addDeployAccountTransaction"
params: AddDeployAccountTransactionParameters
result: AddDeployAccountTransactionResult
}
| {
type: "starknet_signTypedData"
params: TypedData
result: string[]
}

avimak marked this conversation as resolved.
Show resolved Hide resolved
export interface IStarknetWindowObject {
export interface StarknetWindowObject {
id: string
name: string
version: string
icon: string
icon: string | { dark: string; light: string }
request: <T extends RpcMessage>(
call: Omit<T, "result">,
) => Promise<T["result"]>
enable: (options?: { starknetVersion?: "v4" | "v5" }) => Promise<string[]>
isPreauthorized: () => Promise<boolean>
avimak marked this conversation as resolved.
Show resolved Hide resolved
on: <E extends WalletEvents>(
event: E["type"],
handleEvent: E["handler"],
Expand All @@ -90,34 +283,10 @@ export interface IStarknetWindowObject {
event: E["type"],
handleEvent: E["handler"],
) => void
account?: AccountInterface | AccountInterfaceV4
provider?: ProviderInterface | ProviderInterfaceV4
selectedAddress?: string
chainId?: string
}

export interface ConnectedStarknetWindowObject extends IStarknetWindowObject {
isConnected: true
account: AccountInterface | AccountInterfaceV4
provider: ProviderInterface | ProviderInterfaceV4
selectedAddress: string
chainId: string
}

export interface DisconnectedStarknetWindowObject
extends IStarknetWindowObject {
isConnected: false
}

export type StarknetWindowObject =
| ConnectedStarknetWindowObject
| DisconnectedStarknetWindowObject

declare global {
interface Window {
starknet?: StarknetWindowObject
starknet_braavos?: StarknetWindowObject
starknet_argentX?: StarknetWindowObject
[key: `starknet_${string}`]: StarknetWindowObject | undefined
}
}
30 changes: 15 additions & 15 deletions packages/core/src/__test__/main.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ import { mockStorageFunction } from "./storage.mock"
import {
ArgentXMock,
BraavosMock,
makeAuthorized,
UnknownWalletAMock,
UnknownWalletBMock,
makePreAuthorized,
} from "./wallet.mock"
import { describe, expect, it } from "vitest"

Expand Down Expand Up @@ -105,25 +105,25 @@ describe("getAvailableWallets()", () => {
})
})

describe("getPreAuthorizedWallets()", () => {
it("should return all preauthorized wallets", async () => {
describe("getAuthorizedWallets()", () => {
it("should return all authorized wallets", async () => {
const sn = getWallet({
"starknet-argent": makePreAuthorized(true)(ArgentXMock),
"starknet-braavos": makePreAuthorized(true)(BraavosMock),
"starknet-argent": makeAuthorized(true)(ArgentXMock),
"starknet-braavos": makeAuthorized(true)(BraavosMock),
})
const preauthorizedWallets = await sn.getPreAuthorizedWallets()
expect(preauthorizedWallets.length).toBe(2)
expect(preauthorizedWallets.map((w) => w.id)).contains(ArgentXMock.id)
expect(preauthorizedWallets.map((w) => w.id)).contains(BraavosMock.id)
const authorizedWallets = await sn.getAuthorizedWallets()
expect(authorizedWallets.length).toBe(2)
expect(authorizedWallets.map((w) => w.id)).contains(ArgentXMock.id)
expect(authorizedWallets.map((w) => w.id)).contains(BraavosMock.id)
})
it("should return one preauthorized wallet", async () => {
it("should return one authorized wallet", async () => {
const sn = getWallet({
"starknet-argent": makePreAuthorized(true)(ArgentXMock),
"starknet-braavos": makePreAuthorized(false)(BraavosMock),
"starknet-argent": makeAuthorized(true)(ArgentXMock),
"starknet-braavos": makeAuthorized(false)(BraavosMock),
})
const preauthorizedWallets = await sn.getPreAuthorizedWallets()
expect(preauthorizedWallets.length).toBe(1)
expect(preauthorizedWallets.map((w) => w.id)).contains(ArgentXMock.id)
const authorizedWallets = await sn.getAuthorizedWallets()
expect(authorizedWallets.length).toBe(1)
expect(authorizedWallets.map((w) => w.id)).contains(ArgentXMock.id)
})
})

Expand Down
Loading
Loading