@inco/shield-js 0.0.0-bootstrap.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +359 -0
  3. package/dist/binary.d.ts +3 -0
  4. package/dist/binary.js +16 -0
  5. package/dist/contracts/abi.d.ts +6800 -0
  6. package/dist/contracts/abi.js +8836 -0
  7. package/dist/contracts/index.d.ts +2 -0
  8. package/dist/contracts/index.js +2 -0
  9. package/dist/contracts/utils.d.ts +25 -0
  10. package/dist/contracts/utils.js +28 -0
  11. package/dist/errors.d.ts +125 -0
  12. package/dist/errors.js +91 -0
  13. package/dist/generated/inco/shield/v2/conductor_connect.d.ts +137 -0
  14. package/dist/generated/inco/shield/v2/conductor_connect.js +141 -0
  15. package/dist/generated/inco/shield/v2/deposit_pb.d.ts +103 -0
  16. package/dist/generated/inco/shield/v2/deposit_pb.js +141 -0
  17. package/dist/generated/inco/shield/v2/drafting_pb.d.ts +279 -0
  18. package/dist/generated/inco/shield/v2/drafting_pb.js +372 -0
  19. package/dist/generated/inco/shield/v2/permission_pb.d.ts +443 -0
  20. package/dist/generated/inco/shield/v2/permission_pb.js +639 -0
  21. package/dist/generated/inco/shield/v2/query_pb.d.ts +103 -0
  22. package/dist/generated/inco/shield/v2/query_pb.js +141 -0
  23. package/dist/generated/inco/shield/v2/types_pb.d.ts +166 -0
  24. package/dist/generated/inco/shield/v2/types_pb.js +261 -0
  25. package/dist/index.d.ts +12 -0
  26. package/dist/index.js +19 -0
  27. package/dist/shield/client.d.ts +72 -0
  28. package/dist/shield/client.js +136 -0
  29. package/dist/shield/convert.d.ts +18 -0
  30. package/dist/shield/convert.js +152 -0
  31. package/dist/shield/encryption.d.ts +86 -0
  32. package/dist/shield/encryption.js +180 -0
  33. package/dist/shield/envelope.d.ts +14 -0
  34. package/dist/shield/envelope.js +29 -0
  35. package/dist/shield/index.d.ts +13 -0
  36. package/dist/shield/index.js +11 -0
  37. package/dist/shield/intent.d.ts +977 -0
  38. package/dist/shield/intent.js +188 -0
  39. package/dist/shield/rpc.d.ts +72 -0
  40. package/dist/shield/rpc.js +423 -0
  41. package/dist/shield/shield.eip712.gen.d.ts +396 -0
  42. package/dist/shield/shield.eip712.gen.js +318 -0
  43. package/dist/shield/types.d.ts +119 -0
  44. package/dist/shield/types.js +4 -0
  45. package/dist/shield/userop/gas-estimation.d.ts +36 -0
  46. package/dist/shield/userop/gas-estimation.js +284 -0
  47. package/dist/shield/userop/index.d.ts +1 -0
  48. package/dist/shield/userop/index.js +1 -0
  49. package/dist/shield/userop/token-exchange.d.ts +54 -0
  50. package/dist/shield/userop/token-exchange.js +165 -0
  51. package/dist/shield/userop/types.d.ts +91 -0
  52. package/dist/shield/userop/types.js +4 -0
  53. package/dist/shield/userop/userOp.d.ts +26 -0
  54. package/dist/shield/userop/userOp.js +98 -0
  55. package/dist/shield/utils/chain.d.ts +2 -0
  56. package/dist/shield/utils/chain.js +8 -0
  57. package/dist/uniswap-adapter/config.d.ts +34 -0
  58. package/dist/uniswap-adapter/config.js +45 -0
  59. package/dist/uniswap-adapter/find-pools.d.ts +91 -0
  60. package/dist/uniswap-adapter/find-pools.js +108 -0
  61. package/dist/uniswap-adapter/index.d.ts +10 -0
  62. package/dist/uniswap-adapter/index.js +13 -0
  63. package/dist/uniswap-adapter/swap.d.ts +344 -0
  64. package/dist/uniswap-adapter/swap.js +309 -0
  65. package/package.json +72 -0
@@ -0,0 +1,188 @@
1
+ import { createPublicClient, encodeAbiParameters, getAbiItem, http, } from 'viem';
2
+ import { createBundlerClient, entryPoint07Address, } from 'viem/account-abstraction';
3
+ import { shieldAbiStubAbi } from '../contracts/abi.js';
4
+ import { BundlerGasEstimateIncomplete } from '../errors.js';
5
+ import { IntentKind } from '../generated/inco/shield/v2/drafting_pb.js';
6
+ import { userOpFromIntentForGasEstimation } from './userop/gas-estimation.js';
7
+ import { convertEthWeiToTokenUnits } from './userop/token-exchange.js';
8
+ import { getChainFromId } from './utils/chain.js';
9
+ // Main function of this file: createIntent and createDelegatedIntent
10
+ /**
11
+ * Create an intent with gas estimation. Generic over the intent kind: the returned
12
+ * `Intent` variant matches the kind of the supplied `IntentOp`.
13
+ */
14
+ async function createIntent(intentOp, salt, signer, shieldConfig, publicClient, gas, bundlerUrl) {
15
+ const chain = getChainFromId(Number(shieldConfig.chainId));
16
+ const bundlerPublicClient = createPublicClient({
17
+ chain,
18
+ transport: http(chain.rpcUrls.default.http[0]),
19
+ });
20
+ const bundlerClient = createBundlerClient({
21
+ client: bundlerPublicClient,
22
+ transport: http(bundlerUrl),
23
+ });
24
+ // Step1: build a placeholder UserOp for the bundler to estimate against
25
+ const placeholderUserOp = await userOpFromIntentForGasEstimation(intentOp, signer, shieldConfig, publicClient, gas);
26
+ // Step2: ask the bundler to fill in the gas limits
27
+ const gasEstimate = await bundlerClient.estimateUserOperationGas({
28
+ entryPointAddress: entryPoint07Address,
29
+ sender: placeholderUserOp.sender,
30
+ nonce: placeholderUserOp.nonce,
31
+ callData: placeholderUserOp.callData,
32
+ signature: placeholderUserOp.signature,
33
+ preVerificationGas: placeholderUserOp.preVerificationGas,
34
+ verificationGasLimit: placeholderUserOp.verificationGasLimit,
35
+ callGasLimit: placeholderUserOp.callGasLimit,
36
+ maxFeePerGas: placeholderUserOp.maxFeePerGas,
37
+ maxPriorityFeePerGas: placeholderUserOp.maxPriorityFeePerGas,
38
+ paymasterVerificationGasLimit: placeholderUserOp.paymasterVerificationGasLimit,
39
+ paymasterPostOpGasLimit: placeholderUserOp.paymasterPostOpGasLimit,
40
+ });
41
+ const preVerificationGas = gasEstimate.preVerificationGas;
42
+ const verificationGasLimit = gasEstimate.verificationGasLimit;
43
+ const callGasLimit = gasEstimate.callGasLimit;
44
+ const paymasterVerificationGasLimit = gasEstimate.paymasterVerificationGasLimit;
45
+ const paymasterPostOpGasLimit = gasEstimate.paymasterPostOpGasLimit;
46
+ const missingFields = [];
47
+ if (preVerificationGas === undefined)
48
+ missingFields.push('preVerificationGas');
49
+ if (verificationGasLimit === undefined)
50
+ missingFields.push('verificationGasLimit');
51
+ if (callGasLimit === undefined)
52
+ missingFields.push('callGasLimit');
53
+ if (paymasterVerificationGasLimit === undefined)
54
+ missingFields.push('paymasterVerificationGasLimit');
55
+ if (paymasterPostOpGasLimit === undefined)
56
+ missingFields.push('paymasterPostOpGasLimit');
57
+ if (preVerificationGas === undefined ||
58
+ verificationGasLimit === undefined ||
59
+ callGasLimit === undefined ||
60
+ paymasterVerificationGasLimit === undefined ||
61
+ paymasterPostOpGasLimit === undefined) {
62
+ throw new BundlerGasEstimateIncomplete({
63
+ message: 'Bundler did not return all required gas sub-limits',
64
+ missingFields,
65
+ });
66
+ }
67
+ // Step3: derive `maxAmount` — the cap the user signs over, denominated
68
+ // in `gas.assetId` smallest-units (e.g. 1_000_000 = 1 USDC).
69
+ //
70
+ // We compute that ETH-wei cost, then convert to token units via a Chainlink RAY-precision exchange rate, ceiling-
71
+ // rounded to match the paymaster's on-chain rounding so the signed cap can never come in below what `_postOp` actually charges.
72
+ const totalGasUnits = preVerificationGas +
73
+ verificationGasLimit +
74
+ callGasLimit +
75
+ paymasterVerificationGasLimit +
76
+ paymasterPostOpGasLimit;
77
+ const maxGasCostWei = totalGasUnits * gas.maxFeePerGas;
78
+ const maxAmount = await convertEthWeiToTokenUnits(publicClient, gas.assetId, maxGasCostWei);
79
+ // Bake in every bundler-estimated limit — the same five summed into
80
+ // `totalGasUnits` above — so the signed `Gas` matches the cap derived
81
+ // from it. Writing back only `callGasLimit` would leave the intent's
82
+ // other limits at the caller's placeholders, inconsistent with `maxAmount`.
83
+ const estimatedGas = {
84
+ ...gas,
85
+ callGasLimit,
86
+ verificationGasLimit,
87
+ preVerificationGas,
88
+ paymasterVerificationGasLimit,
89
+ paymasterPostOpGasLimit,
90
+ maxAmount,
91
+ };
92
+ return assembleIntent(intentOp.op, signer, estimatedGas, salt);
93
+ }
94
+ async function createDelegatedIntent(intentOp, salt, spender, attestation, signer, shieldConfig, publicClient, gas, bundlerUrl) {
95
+ const intent = await createIntent(intentOp, salt, signer, shieldConfig, publicClient, gas, bundlerUrl);
96
+ return { intent, spender, attestation };
97
+ }
98
+ function assembleIntent(op, signer, gas, salt) {
99
+ return { op, signer: signer.address, gas, salt };
100
+ }
101
+ // Exported functions
102
+ export async function createTransferIntent(transferIntentOp, salt, signer, shieldConfig, publicClient, gas, bundlerUrl) {
103
+ return createIntent({ kind: IntentKind.TRANSFER, op: transferIntentOp }, salt, signer, shieldConfig, publicClient, gas, bundlerUrl);
104
+ }
105
+ export async function createWithdrawIntent(withdrawalIntentOp, salt, signer, shieldConfig, publicClient, gas, bundlerUrl) {
106
+ return createIntent({ kind: IntentKind.WITHDRAW, op: withdrawalIntentOp }, salt, signer, shieldConfig, publicClient, gas, bundlerUrl);
107
+ }
108
+ export async function createDefiInteractionIntent(defiInteractionIntentOp, salt, signer, shieldConfig, publicClient, gas, bundlerUrl) {
109
+ return createIntent({ kind: IntentKind.DEFI_INTERACTION, op: defiInteractionIntentOp }, salt, signer, shieldConfig, publicClient, gas, bundlerUrl);
110
+ }
111
+ export async function createIndividualRevocationIntent(individualRevocationIntentOp, salt, signer, shieldConfig, publicClient, gas, bundlerUrl) {
112
+ return createIntent({
113
+ kind: IntentKind.INDIVIDUAL_REVOCATION,
114
+ op: individualRevocationIntentOp,
115
+ }, salt, signer, shieldConfig, publicClient, gas, bundlerUrl);
116
+ }
117
+ export async function createUserWideRevocationIntent(userWideRevocationIntentOp, salt, signer, shieldConfig, publicClient, gas, bundlerUrl) {
118
+ return createIntent({ kind: IntentKind.USER_WIDE_REVOCATION, op: userWideRevocationIntentOp }, salt, signer, shieldConfig, publicClient, gas, bundlerUrl);
119
+ }
120
+ export async function createDelegatedTransferIntent(transferIntentOp, salt, spender, attestation, signer, shieldConfig, publicClient, gas, bundlerUrl) {
121
+ return createDelegatedIntent({ kind: IntentKind.DELEGATED_TRANSFER, op: transferIntentOp }, salt, spender, attestation, signer, shieldConfig, publicClient, gas, bundlerUrl);
122
+ }
123
+ export async function createDelegatedWithdrawIntent(withdrawalIntentOp, salt, spender, attestation, signer, shieldConfig, publicClient, gas, bundlerUrl) {
124
+ return createDelegatedIntent({ kind: IntentKind.DELEGATED_WITHDRAW, op: withdrawalIntentOp }, salt, spender, attestation, signer, shieldConfig, publicClient, gas, bundlerUrl);
125
+ }
126
+ export async function createDelegatedDefiInteractionIntent(defiInteractionIntentOp, salt, spender, attestation, signer, shieldConfig, publicClient, gas, bundlerUrl) {
127
+ return createDelegatedIntent({
128
+ kind: IntentKind.DELEGATED_DEFI_INTERACTION,
129
+ op: defiInteractionIntentOp,
130
+ }, salt, spender, attestation, signer, shieldConfig, publicClient, gas, bundlerUrl);
131
+ }
132
+ // ABI Encoding
133
+ const transferIntentAbi = getAbiItem({
134
+ abi: shieldAbiStubAbi,
135
+ name: 'transferIntent',
136
+ }).inputs[0];
137
+ const withdrawalIntentAbi = getAbiItem({
138
+ abi: shieldAbiStubAbi,
139
+ name: 'withdrawalIntent',
140
+ }).inputs[0];
141
+ const defiInteractionIntentAbi = getAbiItem({
142
+ abi: shieldAbiStubAbi,
143
+ name: 'defiInteractionIntent',
144
+ }).inputs[0];
145
+ const individualRevocationIntentAbi = getAbiItem({
146
+ abi: shieldAbiStubAbi,
147
+ name: 'individualRevocationIntent',
148
+ }).inputs[0];
149
+ const userWideRevocationIntentAbi = getAbiItem({
150
+ abi: shieldAbiStubAbi,
151
+ name: 'userWideRevocationIntent',
152
+ }).inputs[0];
153
+ const delegatedTransferIntentAbi = getAbiItem({
154
+ abi: shieldAbiStubAbi,
155
+ name: 'delegatedTransferIntent',
156
+ }).inputs[0];
157
+ const delegatedWithdrawalIntentAbi = getAbiItem({
158
+ abi: shieldAbiStubAbi,
159
+ name: 'delegatedWithdrawalIntent',
160
+ }).inputs[0];
161
+ const delegatedDefiInteractionIntentAbi = getAbiItem({
162
+ abi: shieldAbiStubAbi,
163
+ name: 'delegatedDefiInteractionIntent',
164
+ }).inputs[0];
165
+ /**
166
+ * Mapping from the intent kind to the abi item.
167
+ */
168
+ export const intentAbi = {
169
+ [IntentKind.TRANSFER]: transferIntentAbi,
170
+ [IntentKind.WITHDRAW]: withdrawalIntentAbi,
171
+ [IntentKind.DEFI_INTERACTION]: defiInteractionIntentAbi,
172
+ [IntentKind.INDIVIDUAL_REVOCATION]: individualRevocationIntentAbi,
173
+ [IntentKind.USER_WIDE_REVOCATION]: userWideRevocationIntentAbi,
174
+ [IntentKind.DELEGATED_TRANSFER]: delegatedTransferIntentAbi,
175
+ [IntentKind.DELEGATED_WITHDRAW]: delegatedWithdrawalIntentAbi,
176
+ [IntentKind.DELEGATED_DEFI_INTERACTION]: delegatedDefiInteractionIntentAbi,
177
+ };
178
+ /**
179
+ * ABI-encode an intent.
180
+ */
181
+ export function encodeIntent(kind, intent) {
182
+ // viem's `encodeAbiParameters` over-constrains the value tuple when the
183
+ // parameter list is a union. `intentAbi[kind]` and `IntentMapping[K]['intent']`
184
+ // are paired by construction, so we erase the union to a single `AbiParameter`
185
+ // before encoding.
186
+ const params = [intentAbi[kind]];
187
+ return encodeAbiParameters(params, [intent]);
188
+ }
@@ -0,0 +1,72 @@
1
+ import type { Client } from '@connectrpc/connect';
2
+ import { type Hex } from 'viem';
3
+ import type { UserOperation } from 'viem/account-abstraction';
4
+ import type { ConductorService as ConductorServiceType } from '../generated/inco/shield/v2/conductor_connect.js';
5
+ import { type PermissionAttestation, type PermissionAttestationRequest, type TransferIntentOp, type WithdrawalIntentOp } from './shield.eip712.gen.js';
6
+ import type { Balance, DepositAttestation, GetBalanceParams, GetPermissionDetailsParams, GetPermissionsByOwnerParams, GetPermissionsBySpenderParams, PermissionDetails, PermissionInfo, PermissionIntent, RequestDepositAttestationParams, ShieldSigner } from './types.js';
7
+ import type { ENTRYPOINT_VERSION } from './userop/types.js';
8
+ export type Rpc = Client<typeof ConductorServiceType>;
9
+ export type RpcContext = {
10
+ rpc: Rpc;
11
+ domainSeparator: Hex;
12
+ signer: ShieldSigner;
13
+ teePublicKey: CryptoKey;
14
+ };
15
+ /**
16
+ * Inputs to the salted `permissionId` formula. Mirrors `PermissionIntent` minus
17
+ * `intentExpiry` (which gates issuance, not identity).
18
+ */
19
+ export type PermissionIdInput = Omit<PermissionIntent, 'intentExpiry'>;
20
+ /**
21
+ * `permissionId = keccak256(abi.encode(...))` over the 9 identity fields. Must
22
+ * match the umbo helper bit-for-bit; cross-checked in `sdk/test/permission-id.test.ts`.
23
+ *
24
+ * Off-chain only — no on-chain code recomputes this.
25
+ */
26
+ export declare function computePermissionId(input: PermissionIdInput): Hex;
27
+ export declare function issueTransfer(ctx: RpcContext, intentOp: TransferIntentOp): Promise<{
28
+ userOp: UserOperation<typeof ENTRYPOINT_VERSION>;
29
+ }>;
30
+ export declare function issueWithdraw(ctx: RpcContext, intentOp: WithdrawalIntentOp): Promise<{
31
+ userOp: UserOperation<typeof ENTRYPOINT_VERSION>;
32
+ }>;
33
+ /**
34
+ * Owner-side issuance flow: sign the intent, hand it to the TEE, receive a
35
+ * long-lived `PermissionAttestation` for the spender. The spender presents
36
+ * the attestation on every subsequent draft.
37
+ *
38
+ * Doc-mandated client cross-check: recompute `permissionId` locally from
39
+ * intent terms and verify the TEE's returned attestation matches. A mismatch
40
+ * means the TEE substituted a different identity — fail closed.
41
+ */
42
+ export declare function requestPermissionAttestation(ctx: RpcContext, req: PermissionAttestationRequest): Promise<PermissionAttestation>;
43
+ /**
44
+ * Spender-side delegated transfer draft: sign the transfer intent, present the
45
+ * owner's `PermissionAttestation` to the TEE, receive a spending note. The TEE
46
+ * verifies the attestation signature and runs all 7 validation steps before
47
+ * drafting the spend.
48
+ */
49
+ export declare function issueDelegatedTransfer(ctx: RpcContext, intentOp: TransferIntentOp, attestation: PermissionAttestation): Promise<{
50
+ userOp: UserOperation<typeof ENTRYPOINT_VERSION>;
51
+ }>;
52
+ /**
53
+ * The resulting cheque settles byte-identically to a direct withdraw —
54
+ * observers cannot distinguish delegated from direct.
55
+ */
56
+ export declare function issueDelegatedWithdraw(ctx: RpcContext, intentOp: WithdrawalIntentOp, attestation: PermissionAttestation): Promise<{
57
+ userOp: UserOperation<typeof ENTRYPOINT_VERSION>;
58
+ }>;
59
+ export declare function revokeOne(ctx: RpcContext, params: {
60
+ permissionId: Hex;
61
+ }): Promise<{
62
+ userOp: UserOperation<typeof ENTRYPOINT_VERSION>;
63
+ }>;
64
+ export declare function revokeAll(ctx: RpcContext): Promise<{
65
+ userOp: UserOperation<typeof ENTRYPOINT_VERSION>;
66
+ }>;
67
+ export declare function getBalance(ctx: RpcContext, params: GetBalanceParams): Promise<Balance>;
68
+ export declare function requestDepositAttestation(ctx: RpcContext, params: RequestDepositAttestationParams): Promise<DepositAttestation>;
69
+ export declare function getPermissionsByOwner(ctx: RpcContext, params: GetPermissionsByOwnerParams): Promise<PermissionInfo[]>;
70
+ export declare function getPermissionsBySpender(ctx: RpcContext, params: GetPermissionsBySpenderParams): Promise<PermissionInfo[]>;
71
+ export declare function getPermissionDetails(ctx: RpcContext, params: GetPermissionDetailsParams): Promise<PermissionDetails>;
72
+ export declare function getOwnerGeneration(ctx: RpcContext): Promise<bigint>;