@inco/js 0.1.31 → 0.1.33
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.
- package/README.md +28 -57
- package/dist/binary.js +67 -0
- package/dist/chain.js +24 -0
- package/dist/encryption/encryption.js +98 -0
- package/dist/encryption/index.cjs +132 -123
- package/dist/encryption/index.js +2 -0
- package/dist/encryption/index.mjs +132 -123
- package/dist/fhevm/fhe-environment.js +8 -0
- package/dist/fhevm/fhevm.js +139 -0
- package/dist/fhevm/index.js +2 -0
- package/dist/fhevm/reencrypt.js +123 -0
- package/dist/fhevm/tfhe.js +324 -0
- package/dist/fhevm/types.js +26 -0
- package/dist/generated/abis/addTwo.js +59 -0
- package/dist/generated/abis/inco-fhevm.js +6242 -0
- package/dist/generated/abis/index.js +3 -0
- package/dist/generated/abis/lightning.js +12489 -0
- package/dist/generated/es/cosmos/ics23/v1/proofs_pb.js +198 -0
- package/dist/generated/es/cosmos/msg/v1/msg_pb.js +33 -0
- package/dist/generated/es/cosmos_proto/cosmos_pb.js +115 -0
- package/dist/generated/es/google/api/annotations_pb.js +27 -0
- package/dist/generated/es/google/api/http_pb.js +34 -0
- package/dist/generated/es/inco/fhe/v1/events_pb.js +21 -0
- package/dist/generated/es/inco/fhe/v1/genesis_pb.js +46 -0
- package/dist/generated/es/inco/fhe/v1/query_pb.js +108 -0
- package/dist/generated/es/inco/fhe/v1/tx_pb.js +108 -0
- package/dist/generated/es/inco/fhe/v1/types_pb.js +133 -0
- package/dist/generated/es/inco/kms/lite/v1/kms_service_pb.js +43 -0
- package/dist/generated/es/inco/kms/lite/v1/types_pb.js +44 -0
- package/dist/generated/es/inco/preflight/v1/genesis_pb.js +20 -0
- package/dist/generated/es/inco/preflight/v1/query_pb.js +38 -0
- package/dist/generated/es/inco/preflight/v1/tx_pb.js +48 -0
- package/dist/generated/es/inco/preflight/v1/types_pb.js +34 -0
- package/dist/generated/es/kms/base_pb.js +238 -0
- package/dist/generated/es/sf/ethereum/type/v2/type_pb.js +571 -0
- package/dist/generated/fhe-environments.js +15 -0
- package/dist/generated/lightning.js +399 -0
- package/dist/generated/local-node.js +8 -0
- package/dist/generated/ts/amino/amino.js +8 -0
- package/dist/generated/ts/cometbft/abci/v1/types.js +5063 -0
- package/dist/generated/ts/cometbft/crypto/v1/keys.js +105 -0
- package/dist/generated/ts/cometbft/crypto/v1/proof.js +430 -0
- package/dist/generated/ts/cometbft/types/v1/params.js +713 -0
- package/dist/generated/ts/cometbft/types/v1/validator.js +353 -0
- package/dist/generated/ts/cosmos/app/v1alpha1/module.js +218 -0
- package/dist/generated/ts/cosmos/msg/v1/msg.js +8 -0
- package/dist/generated/ts/cosmos_proto/cosmos.js +211 -0
- package/dist/generated/ts/gogoproto/gogo.js +8 -0
- package/dist/generated/ts/google/api/annotations.js +8 -0
- package/dist/generated/ts/google/api/http.js +353 -0
- package/dist/generated/ts/google/protobuf/descriptor.js +5070 -0
- package/dist/generated/ts/google/protobuf/duration.js +90 -0
- package/dist/generated/ts/google/protobuf/timestamp.js +90 -0
- package/dist/generated/ts/google/protobuf/wrappers.js +506 -0
- package/dist/generated/ts/inco/abci/v1/types.js +70 -0
- package/dist/generated/ts/inco/fhe/module/v1/module.js +63 -0
- package/dist/generated/ts/inco/fhe/v1/events.js +187 -0
- package/dist/generated/ts/inco/fhe/v1/genesis.js +711 -0
- package/dist/generated/ts/inco/fhe/v1/query.js +1391 -0
- package/dist/generated/ts/inco/fhe/v1/tx.js +1233 -0
- package/dist/generated/ts/inco/fhe/v1/types.js +985 -0
- package/dist/generated/ts/inco/originchain/module/v1/module.js +63 -0
- package/dist/generated/ts/inco/originchain/v1/abci.js +328 -0
- package/dist/generated/ts/inco/originchain/v1/events.js +213 -0
- package/dist/generated/ts/inco/originchain/v1/genesis.js +66 -0
- package/dist/generated/ts/inco/originchain/v1/query.js +277 -0
- package/dist/generated/ts/inco/originchain/v1/tx.js +137 -0
- package/dist/generated/ts/inco/originchain/v1/types.js +200 -0
- package/dist/generated/ts/inco/preflight/module/v1/module.js +63 -0
- package/dist/generated/ts/inco/preflight/v1/genesis.js +182 -0
- package/dist/generated/ts/inco/preflight/v1/query.js +256 -0
- package/dist/generated/ts/inco/preflight/v1/tx.js +445 -0
- package/dist/generated/ts/inco/preflight/v1/types.js +395 -0
- package/dist/handle.js +94 -0
- package/dist/index.cjs +140 -131
- package/dist/index.js +6 -0
- package/dist/index.mjs +140 -131
- package/dist/l1/client.js +93 -0
- package/dist/l1/index.js +3 -0
- package/dist/l1/preflight.js +39 -0
- package/dist/lite/deployments.js +17 -0
- package/dist/lite/ecies.js +124 -0
- package/dist/lite/hadu.js +36 -0
- package/dist/lite/index.cjs +186 -146
- package/dist/lite/index.js +7 -0
- package/dist/lite/index.mjs +3890 -3788
- package/dist/lite/lightning.js +179 -0
- package/dist/lite/reencrypt.d.ts +1 -0
- package/dist/lite/reencrypt.js +148 -0
- package/dist/local/index.cjs +25 -2573
- package/dist/local/index.js +2 -0
- package/dist/local/index.mjs +5352 -7837
- package/dist/local/local-node.js +24 -0
- package/dist/reencryption/eip712.js +81 -0
- package/dist/reencryption/index.cjs +132 -123
- package/dist/reencryption/index.js +3 -0
- package/dist/reencryption/index.mjs +132 -123
- package/dist/reencryption/types.js +2 -0
- package/dist/schema.js +15 -0
- package/dist/viem.d.ts +53 -52
- package/dist/viem.js +8 -0
- package/package.json +11 -48
@@ -0,0 +1,179 @@
|
|
1
|
+
import { hexToBytes } from 'viem';
|
2
|
+
import { baseSepolia } from 'viem/chains';
|
3
|
+
import { HexString, parseAddress } from '../binary';
|
4
|
+
import { encryptionSchemes } from '../encryption';
|
5
|
+
import { lightningDeployments } from '../generated/lightning';
|
6
|
+
import { localNodeLightningConfig } from '../generated/local-node';
|
7
|
+
import { handleTypes } from '../handle';
|
8
|
+
import { parse } from '../schema';
|
9
|
+
import { decodeSecp256k1PublicKey, generateSecp256k1Keypair, getEciesEncryptor } from './ecies';
|
10
|
+
import { getKmsClient, incoLiteReencryptor } from './reencrypt';
|
11
|
+
/**
|
12
|
+
* The Lightning class provides a convenient way to interact with the Inco Lightning contract by binding to a specific
|
13
|
+
* deployment.
|
14
|
+
*/
|
15
|
+
export class Lightning {
|
16
|
+
_deployment;
|
17
|
+
covalidatorUrl;
|
18
|
+
executorAddress;
|
19
|
+
eciesPublicKey;
|
20
|
+
chainId;
|
21
|
+
encryptor;
|
22
|
+
ephemeralKeypair;
|
23
|
+
kmsClient;
|
24
|
+
constructor(_deployment, covalidatorUrl) {
|
25
|
+
this._deployment = _deployment;
|
26
|
+
this.covalidatorUrl = covalidatorUrl;
|
27
|
+
this.executorAddress = parseAddress(_deployment.executorAddress);
|
28
|
+
this.eciesPublicKey = parse(HexString, _deployment.eciesPublicKey);
|
29
|
+
this.chainId = BigInt(_deployment.chainId);
|
30
|
+
this.ephemeralKeypair = generateSecp256k1Keypair();
|
31
|
+
this.kmsClient = getKmsClient(covalidatorUrl);
|
32
|
+
this.encryptor = getEciesEncryptor({
|
33
|
+
scheme: encryptionSchemes.ecies,
|
34
|
+
pubKeyA: decodeSecp256k1PublicKey(hexToBytes(parse(HexString, _deployment.eciesPublicKey))),
|
35
|
+
privKeyB: this.ephemeralKeypair,
|
36
|
+
});
|
37
|
+
}
|
38
|
+
/**
|
39
|
+
* Get a Lightning instance bound to the latest Lightning deployment for the Base Sepolia testnet.
|
40
|
+
*/
|
41
|
+
static baseSepoliaTestnet() {
|
42
|
+
return Lightning.latest('testnet', baseSepolia.id);
|
43
|
+
}
|
44
|
+
/**
|
45
|
+
* Get a Lightning instance bound to our canonical Anvil-based test node and test Covalidator node
|
46
|
+
*
|
47
|
+
* These can be run in docker-compose using images pushed to dockerhub as:
|
48
|
+
* - inconetwork/local-node-anvil
|
49
|
+
* - inconetwork/local-node-covalidator
|
50
|
+
*
|
51
|
+
* See the sample docker-compose file here: https://github.com/Inco-fhevm/lightning-rod/blob/main/docker-compose.yaml
|
52
|
+
*
|
53
|
+
*/
|
54
|
+
static localNode() {
|
55
|
+
return Lightning.custom(localNodeLightningConfig);
|
56
|
+
}
|
57
|
+
/**
|
58
|
+
* Get a Lightning deployment by name or executor address on a particular chain.
|
59
|
+
*
|
60
|
+
* @param id this is an object containing either the pair of name and chainId or the executorAddress and chainId
|
61
|
+
*/
|
62
|
+
static at(id) {
|
63
|
+
const deployment = this.isIdByName(id)
|
64
|
+
? lightningDeployments.find((d) => d.name === id.name && d.chainId === id.chainId)
|
65
|
+
: lightningDeployments.find((d) => d.executorAddress === id.executorAddress && d.chainId === id.chainId);
|
66
|
+
if (!deployment) {
|
67
|
+
throw new Error(`No deployment found for ${JSON.stringify(id)}`);
|
68
|
+
}
|
69
|
+
return new Lightning(deployment, Lightning.getCovalidatorUrl(deployment));
|
70
|
+
}
|
71
|
+
/**
|
72
|
+
* Get a Lightning deployment for a local or custom node
|
73
|
+
*
|
74
|
+
* @param config this is an object containing the executorAddress, eciesPublicKey, chainId and covalidatorUrl.
|
75
|
+
* additional fields past will be made available as part of the `deployment` property.
|
76
|
+
*/
|
77
|
+
static custom(config) {
|
78
|
+
return new Lightning(config, config.covalidatorUrl);
|
79
|
+
}
|
80
|
+
/**
|
81
|
+
* Get the latest deployment for a given pepper, which usually denotes a family of deployments distinct from their
|
82
|
+
* version such as 'devnet', 'testnet', 'mainnet', etc.
|
83
|
+
*
|
84
|
+
* @param pepper the pepper to use to filter the deployments
|
85
|
+
* @param chainId the chainId to use to filter the deployments
|
86
|
+
*/
|
87
|
+
static latestDeployment(pepper, chainId) {
|
88
|
+
// Deployments are sorted so we are guaranteed to get the latest first
|
89
|
+
const latestByPepper = lightningDeployments.find((d) => d.pepper === pepper && d.chainId === chainId);
|
90
|
+
if (!latestByPepper) {
|
91
|
+
// This should not actually happen provided this file compiles since we are extracting the available peppers
|
92
|
+
// from the const itself
|
93
|
+
throw new Error(`No deployment found for pepper ${pepper}`);
|
94
|
+
}
|
95
|
+
return latestByPepper;
|
96
|
+
}
|
97
|
+
/**
|
98
|
+
* Get the latest Lightning deployment for a given pepper amd chainId unconditionally.
|
99
|
+
* Note that if you upgrade the library the latest deployment may change and contracts deployed to a previous version
|
100
|
+
* will not be compatible with the new version.
|
101
|
+
*
|
102
|
+
* @param pepper the pepper to use to filter the deployments
|
103
|
+
* @param chainId the chainId to use to filter the deployments
|
104
|
+
*/
|
105
|
+
static latest(pepper, chainId) {
|
106
|
+
return Lightning.at(Lightning.latestDeployment(pepper, chainId));
|
107
|
+
}
|
108
|
+
/*
|
109
|
+
* Get the latest deployment for a given pepper, which usually denotes a family of deployments distinct from their
|
110
|
+
* version such as 'devnet', 'testnet', 'mainnet', etc.
|
111
|
+
*/
|
112
|
+
get deployment() {
|
113
|
+
return { ...this._deployment };
|
114
|
+
}
|
115
|
+
/**
|
116
|
+
* Encrypt a value using the public ECIES key of the Lightning deployment.
|
117
|
+
*
|
118
|
+
* @param value a boolean or numeric value to encrypt
|
119
|
+
* @param accountAddress the address of the account interacting with the dapp contract, normally an Externally Owned Account (EOA)
|
120
|
+
* @param dappAddress the address of the dapp contract that interacts with the Inco Lightning contract or library
|
121
|
+
*/
|
122
|
+
async encrypt(value, { accountAddress, dappAddress }) {
|
123
|
+
const { ciphertext } = await this.encryptor({
|
124
|
+
plaintext: Lightning.plaintextFromValue(value),
|
125
|
+
context: {
|
126
|
+
hostChainId: this.chainId,
|
127
|
+
aclAddress: this.executorAddress,
|
128
|
+
userAddress: parseAddress(accountAddress),
|
129
|
+
contractAddress: parseAddress(dappAddress),
|
130
|
+
},
|
131
|
+
});
|
132
|
+
return ciphertext.value;
|
133
|
+
}
|
134
|
+
/**
|
135
|
+
* Obtain a reencryptor for a particular Externally Owned Account (EOA) to request decrypted values.
|
136
|
+
* The account associated with the walletClient must have permissions to decrypt the handle or ciphertext passed
|
137
|
+
* to the reencryptor function.
|
138
|
+
*
|
139
|
+
* @param walletClient the wallet client to use for signing the reencrypt request.
|
140
|
+
*/
|
141
|
+
getReencryptor(walletClient) {
|
142
|
+
return incoLiteReencryptor({
|
143
|
+
walletClient,
|
144
|
+
kmsConnectRpcEndpointOrClient: this.kmsClient,
|
145
|
+
chainId: this.chainId,
|
146
|
+
ephemeralKeypair: this.ephemeralKeypair,
|
147
|
+
});
|
148
|
+
}
|
149
|
+
/**
|
150
|
+
* Get the GRPC endpoint for the covalidator that services this deployment.
|
151
|
+
*/
|
152
|
+
static getCovalidatorUrl(deployment) {
|
153
|
+
const { executorAddress, chainId, pepper } = deployment;
|
154
|
+
return `https://${executorAddress.toLowerCase()}.${chainId}.${pepper}.inco.org`;
|
155
|
+
}
|
156
|
+
static isIdByName(id) {
|
157
|
+
return id.name !== undefined;
|
158
|
+
}
|
159
|
+
static plaintextFromValue(value) {
|
160
|
+
if (typeof value === 'boolean') {
|
161
|
+
return {
|
162
|
+
scheme: encryptionSchemes.ecies,
|
163
|
+
type: handleTypes.ebool,
|
164
|
+
value: value,
|
165
|
+
};
|
166
|
+
}
|
167
|
+
else if (typeof value === 'bigint' || typeof value === 'number') {
|
168
|
+
return {
|
169
|
+
scheme: encryptionSchemes.ecies,
|
170
|
+
type: handleTypes.euint256,
|
171
|
+
value: BigInt(value),
|
172
|
+
};
|
173
|
+
}
|
174
|
+
else {
|
175
|
+
throw new Error(`Unsupported type ${typeof value}`);
|
176
|
+
}
|
177
|
+
}
|
178
|
+
}
|
179
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibGlnaHRuaW5nLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2xpdGUvbGlnaHRuaW5nLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUNBLE9BQU8sRUFBa0IsVUFBVSxFQUEyQixNQUFNLE1BQU0sQ0FBQztBQUMzRSxPQUFPLEVBQUUsV0FBVyxFQUFFLE1BQU0sYUFBYSxDQUFDO0FBQzFDLE9BQU8sRUFBVyxTQUFTLEVBQUUsWUFBWSxFQUFFLE1BQU0sV0FBVyxDQUFDO0FBQzdELE9BQU8sRUFBZSxpQkFBaUIsRUFBMEIsTUFBTSxlQUFlLENBQUM7QUFFdkYsT0FBTyxFQUFFLG9CQUFvQixFQUFFLE1BQU0sd0JBQXdCLENBQUM7QUFDOUQsT0FBTyxFQUFFLHdCQUF3QixFQUFFLE1BQU0seUJBQXlCLENBQUM7QUFDbkUsT0FBTyxFQUFFLFdBQVcsRUFBRSxNQUFNLFdBQVcsQ0FBQztBQUV4QyxPQUFPLEVBQUUsS0FBSyxFQUFFLE1BQU0sV0FBVyxDQUFDO0FBQ2xDLE9BQU8sRUFBRSx3QkFBd0IsRUFBRSx3QkFBd0IsRUFBRSxpQkFBaUIsRUFBb0IsTUFBTSxTQUFTLENBQUM7QUFDbEgsT0FBTyxFQUFFLFlBQVksRUFBRSxtQkFBbUIsRUFBRSxNQUFNLGFBQWEsQ0FBQztBQXdDaEU7OztHQUdHO0FBQ0gsTUFBTSxPQUFPLFNBQVM7SUFVRDtJQUNEO0lBVkYsZUFBZSxDQUFVO0lBQ3pCLGNBQWMsQ0FBWTtJQUMxQixPQUFPLENBQVM7SUFFZixTQUFTLENBQXlCO0lBQ2xDLGdCQUFnQixDQUFtQjtJQUNuQyxTQUFTLENBQTRCO0lBRXRELFlBQ21CLFdBQWMsRUFDZixjQUFzQjtRQURyQixnQkFBVyxHQUFYLFdBQVcsQ0FBRztRQUNmLG1CQUFjLEdBQWQsY0FBYyxDQUFRO1FBRXRDLElBQUksQ0FBQyxlQUFlLEdBQUcsWUFBWSxDQUFDLFdBQVcsQ0FBQyxlQUFlLENBQUMsQ0FBQztRQUNqRSxJQUFJLENBQUMsY0FBYyxHQUFHLEtB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
|
package/dist/lite/reencrypt.d.ts
CHANGED
@@ -21,3 +21,4 @@ export declare function defaultCovalidatorGrpc(chain: SupportedChain): string;
|
|
21
21
|
export declare function pulumiCovalidatorGrpc(chain: SupportedChain): string;
|
22
22
|
export declare function lightningDevnetCovalidatorGrpc(chain: SupportedChain): string;
|
23
23
|
export declare function lightningTestnetCovalidatorGrpc(chain: SupportedChain): string;
|
24
|
+
export declare function retryWithBackoff<T>(fn: () => Promise<T>, maxRetries?: number, baseDelayInMs?: number): Promise<T>;
|
@@ -0,0 +1,148 @@
|
|
1
|
+
import { createClient } from '@connectrpc/connect';
|
2
|
+
import { createConnectTransport } from '@connectrpc/connect-web';
|
3
|
+
import { bytesToHex, hexToBytes } from 'viem';
|
4
|
+
import { bytesToBigInt } from '../binary';
|
5
|
+
import { getSupportedChain } from '../chain';
|
6
|
+
import { bigintToPlaintext, encryptionSchemes } from '../encryption/encryption';
|
7
|
+
import { KmsService } from '../generated/es/inco/kms/lite/v1/kms_service_pb';
|
8
|
+
import { getHandleType } from '../handle';
|
9
|
+
import { createEIP712Payload } from '../reencryption/eip712';
|
10
|
+
import { decrypt, generateSecp256k1Keypair } from './ecies';
|
11
|
+
// The domain constants used for basic reencrypts.
|
12
|
+
// Note: for advanced ACL, since the signature is checked on-chain, the domain
|
13
|
+
// and version must match the ones used in the contract. For basic ones, we use
|
14
|
+
// a domain different than the one used on-chain
|
15
|
+
const BASIC_REENCRYPT_DOMAIN = {
|
16
|
+
name: 'IncoReencryption',
|
17
|
+
version: '0.1.0',
|
18
|
+
};
|
19
|
+
// Create an EIP712 payload for the Inco Lite basic reencrypt.
|
20
|
+
export function reencryptEIP712(chainId, ephemeralPubKey) {
|
21
|
+
return createEIP712Payload({
|
22
|
+
chainId,
|
23
|
+
primaryType: 'ReencryptionRequest',
|
24
|
+
primaryTypeFields: [{ name: 'publicKey', type: 'bytes' }],
|
25
|
+
message: {
|
26
|
+
publicKey: bytesToHex(ephemeralPubKey),
|
27
|
+
},
|
28
|
+
domainName: BASIC_REENCRYPT_DOMAIN.name,
|
29
|
+
domainVersion: BASIC_REENCRYPT_DOMAIN.version,
|
30
|
+
});
|
31
|
+
}
|
32
|
+
// Returns the Inco Lite Reencryptor, which can reencrypt a handle using the
|
33
|
+
// Basic ACL.
|
34
|
+
export async function incoLiteReencryptor({ kmsConnectRpcEndpointOrClient, chainId, walletClient, ephemeralKeypair, }) {
|
35
|
+
const kmsClient = getKmsClient(kmsConnectRpcEndpointOrClient || defaultCovalidatorGrpc(getSupportedChain(chainId)));
|
36
|
+
if (!ephemeralKeypair) {
|
37
|
+
ephemeralKeypair = await generateSecp256k1Keypair();
|
38
|
+
}
|
39
|
+
// Sign the EIP712 attesting that the user has access to the private key
|
40
|
+
// corresponding to the ephemeral public key.
|
41
|
+
const eip712Payload = reencryptEIP712(chainId, ephemeralKeypair.encodePublicKey());
|
42
|
+
// Using browser extensions, this step will prompt the user to sign the
|
43
|
+
// payload.
|
44
|
+
const eip712Signature = await walletClient.signTypedData(eip712Payload);
|
45
|
+
return async function reencrypt({ handle }) {
|
46
|
+
const ephemeralPubKey = ephemeralKeypair.encodePublicKey();
|
47
|
+
const reencryptRequest = {
|
48
|
+
$typeName: 'inco.kms.lite.v1.ReencryptRequest',
|
49
|
+
userAddress: walletClient.account.address,
|
50
|
+
ephemeralPubKey,
|
51
|
+
eip712Signature: hexToBytes(eip712Signature),
|
52
|
+
handlesWithProofs: [
|
53
|
+
{
|
54
|
+
$typeName: 'inco.kms.lite.v1.HandleWithProof',
|
55
|
+
handle,
|
56
|
+
aclProof: {
|
57
|
+
$typeName: 'inco.kms.lite.v1.ACLProof',
|
58
|
+
// See advancedacl/session-key.ts for an example of using
|
59
|
+
// Advanced ACL.
|
60
|
+
proof: {
|
61
|
+
case: 'incoLiteBasicAclProof',
|
62
|
+
value: {
|
63
|
+
$typeName: 'inco.kms.lite.v1.IncoLiteBasicACLProof',
|
64
|
+
},
|
65
|
+
},
|
66
|
+
},
|
67
|
+
},
|
68
|
+
],
|
69
|
+
};
|
70
|
+
try {
|
71
|
+
const response = await retryWithBackoff(() => kmsClient.reencrypt(reencryptRequest));
|
72
|
+
return decryptGrpcResponse(response, ephemeralKeypair, handle);
|
73
|
+
}
|
74
|
+
catch (error) {
|
75
|
+
console.log(error);
|
76
|
+
throw error;
|
77
|
+
}
|
78
|
+
};
|
79
|
+
}
|
80
|
+
// Helper function to get a KMS client from a string or a Client instance.
|
81
|
+
export function getKmsClient(kmsConnectRpcEndpointOrClient) {
|
82
|
+
if (typeof kmsConnectRpcEndpointOrClient === 'string') {
|
83
|
+
const transport = createConnectTransport({
|
84
|
+
baseUrl: kmsConnectRpcEndpointOrClient,
|
85
|
+
});
|
86
|
+
return createClient(KmsService, transport);
|
87
|
+
}
|
88
|
+
return kmsConnectRpcEndpointOrClient;
|
89
|
+
}
|
90
|
+
// Decrypt using ECIES the ciphertext in the response.
|
91
|
+
// Even though the proto specifies a list of ciphertexts, our JS SDK
|
92
|
+
// currently only supports a single ciphertext.
|
93
|
+
export async function decryptGrpcResponse(response, ephemeralKeypair, handle) {
|
94
|
+
const reencryptedCt = response.payload?.userCiphertexts[0];
|
95
|
+
if (!reencryptedCt) {
|
96
|
+
throw new Error('No reencrypted ciphertext in the response');
|
97
|
+
}
|
98
|
+
const plaintextBytes = await decrypt(ephemeralKeypair, reencryptedCt.ciphertext);
|
99
|
+
const plaintext = bytesToBigInt(plaintextBytes);
|
100
|
+
return bigintToPlaintext(encryptionSchemes.ecies, getHandleType(handle), plaintext);
|
101
|
+
}
|
102
|
+
// Helper function to return the default gRPC endpoint for the covalidator.
|
103
|
+
// Currently, this returns the covalidator for the Inco Lightning public testnet.
|
104
|
+
export function defaultCovalidatorGrpc(chain) {
|
105
|
+
return lightningTestnetCovalidatorGrpc(chain);
|
106
|
+
}
|
107
|
+
// Helper function to get the gRPC endpoint for the Denver covalidator on the
|
108
|
+
// AWS (Pulumi) setup. This function is a convenience, and might disappear in
|
109
|
+
// the future, if the denver testnet is no longer supported.
|
110
|
+
export function pulumiCovalidatorGrpc(chain) {
|
111
|
+
return `https://grpc.${chain.name.toLowerCase()}.covalidator.denver.inco.org`;
|
112
|
+
}
|
113
|
+
// Helper function to get the devnet gRPC endpoint for the Inco Lightning covalidator.
|
114
|
+
export function lightningDevnetCovalidatorGrpc(chain) {
|
115
|
+
return getCovalidatorGrpcHelper(chain, 'devnet', 'lightning');
|
116
|
+
}
|
117
|
+
// Helper function to get the testnet gRPC endpoint for the Inco Lightning covalidator.
|
118
|
+
export function lightningTestnetCovalidatorGrpc(chain) {
|
119
|
+
return getCovalidatorGrpcHelper(chain, 'testnet', 'lightning');
|
120
|
+
}
|
121
|
+
// Convert camelCase to dash-case.
|
122
|
+
function camelToDashCase(str) {
|
123
|
+
return str.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase();
|
124
|
+
}
|
125
|
+
// Small helper, as our GCP covalidator URLs are in a specific format.
|
126
|
+
function getCovalidatorGrpcHelper(chain, network, cluster) {
|
127
|
+
return `https://grpc.${camelToDashCase(chain.name)}.${cluster}.${network}.inco.org`;
|
128
|
+
}
|
129
|
+
// Helper function to implement exponential backoff retry logic
|
130
|
+
export async function retryWithBackoff(fn, maxRetries = 3, baseDelayInMs = 1000) {
|
131
|
+
let lastError;
|
132
|
+
for (let attempt = 0; attempt < maxRetries; attempt++) {
|
133
|
+
try {
|
134
|
+
return await fn();
|
135
|
+
}
|
136
|
+
catch (error) {
|
137
|
+
lastError = error;
|
138
|
+
if (attempt === maxRetries - 1) {
|
139
|
+
break;
|
140
|
+
}
|
141
|
+
const delay = baseDelayInMs * Math.pow(2, attempt);
|
142
|
+
const jitter = delay * (0.8 + Math.random() * 0.4); // random jitter, 80% to 120% of the delay
|
143
|
+
await new Promise((resolve) => setTimeout(resolve, jitter));
|
144
|
+
}
|
145
|
+
}
|
146
|
+
throw lastError;
|
147
|
+
}
|
148
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVlbmNyeXB0LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2xpdGUvcmVlbmNyeXB0LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBVSxZQUFZLEVBQUUsTUFBTSxxQkFBcUIsQ0FBQztBQUMzRCxPQUFPLEVBQUUsc0JBQXNCLEVBQUUsTUFBTSx5QkFBeUIsQ0FBQztBQUNqRSxPQUFPLEVBQVcsVUFBVSxFQUFjLFVBQVUsRUFBMkIsTUFBTSxNQUFNLENBQUM7QUFDNUYsT0FBTyxFQUFFLGFBQWEsRUFBRSxNQUFNLFdBQVcsQ0FBQztBQUMxQyxPQUFPLEVBQUUsaUJBQWlCLEVBQWtCLE1BQU0sVUFBVSxDQUFDO0FBQzdELE9BQU8sRUFBRSxpQkFBaUIsRUFBZSxpQkFBaUIsRUFBb0IsTUFBTSwwQkFBMEIsQ0FBQztBQUMvRyxPQUFPLEVBQUUsVUFBVSxFQUF1QyxNQUFNLGlEQUFpRCxDQUFDO0FBQ2xILE9BQU8sRUFBRSxhQUFhLEVBQVUsTUFBTSxXQUFXLENBQUM7QUFFbEQsT0FBTyxFQUFFLG1CQUFtQixFQUFFLE1BQU0sd0JBQXdCLENBQUM7QUFDN0QsT0FBTyxFQUFFLE9BQU8sRUFBRSx3QkFBd0IsRUFBb0IsTUFBTSxTQUFTLENBQUM7QUFpQjlFLGtEQUFrRDtBQUNsRCw4RUFBOEU7QUFDOUUsK0VBQStFO0FBQy9FLGdEQUFnRDtBQUNoRCxNQUFNLHNCQUFzQixHQUFHO0lBQzdCLElBQUksRUFBRSxrQkFBa0I7SUFDeEIsT0FBTyxFQUFFLE9BQU87Q0FDakIsQ0FBQztBQUVGLDhEQUE4RDtBQUM5RCxNQUFNLFVBQVUsZUFBZSxDQUFDLE9BQWUsRUFBRSxlQUEyQjtJQUMxRSxPQUFPLG1CQUFtQixDQUFDO1FBQ3pCLE9BQU87UUFDUCxXQUFXLEVBQUUscUJBQXFCO1FBQ2xDLGlCQUFpQixFQUFFLENBQUMsRUFBRSxJQUFJLEVBQUUsV0FBVyxFQUFFLElBQUksRUFBRSxPQUFPLEVBQUUsQ0FBQztRQUN6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
|