Skip to content

Commit

Permalink
Add support for SecretNetwork v1.15
Browse files Browse the repository at this point in the history
  • Loading branch information
iKapitonau committed Oct 4, 2024
1 parent 1e9ca5a commit 318c0db
Show file tree
Hide file tree
Showing 26 changed files with 971 additions and 61 deletions.
47 changes: 38 additions & 9 deletions packages/background/src/secret-wasm/enigma-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,18 @@ import { generateKeyPair, sharedKey as x25519 } from "curve25519-js";
import { hkdf } from "@noble/hashes/hkdf";
import { sha256 } from "@noble/hashes/sha256";
import * as miscreant from "miscreant";
import { simpleFetch } from "@keplr-wallet/simple-fetch";
import {
simpleFetch,
isSimpleFetchError,
SimpleFetchError,
} from "@keplr-wallet/simple-fetch";
import { Buffer } from "buffer/";
import { ChainIdHelper } from "@keplr-wallet/cosmos";

const cryptoProvider = new miscreant.PolyfillCryptoProvider();

export interface EncryptionUtils {
isNewApi: boolean;
getPubkey: () => Promise<Uint8Array>;
decrypt: (ciphertext: Uint8Array, nonce: Uint8Array) => Promise<Uint8Array>;
encrypt: (contractCodeHash: string, msg: object) => Promise<Uint8Array>;
Expand All @@ -29,6 +34,7 @@ const secretConsensusIoPubKey = new Uint8Array(
export class EnigmaUtils implements EncryptionUtils {
private readonly privkey: Uint8Array;
public readonly pubkey: Uint8Array;
public isNewApi: boolean;
private consensusIoPubKey: Uint8Array = new Uint8Array(); // cache

public constructor(
Expand All @@ -49,6 +55,7 @@ export class EnigmaUtils implements EncryptionUtils {
if (ChainIdHelper.parse(chainId).identifier === "secret") {
this.consensusIoPubKey = secretConsensusIoPubKey;
}
this.isNewApi = false;
}

private static secureRandom(count: number): Uint8Array {
Expand All @@ -71,14 +78,36 @@ export class EnigmaUtils implements EncryptionUtils {
return this.consensusIoPubKey;
}

const response = await simpleFetch<{ result: { TxKey: string } }>(
this.url,
"/reg/tx-key"
);

this.consensusIoPubKey = new Uint8Array(
Buffer.from(response.data.result.TxKey, "base64")
);
// try to fetch from the old API
try {
const response = await simpleFetch<{ result: { TxKey: string } }>(
this.url,
"/reg/tx-key"
);

this.consensusIoPubKey = new Uint8Array(
Buffer.from(response.data.result.TxKey, "base64")
);
} catch (e: any) {
if (
!isSimpleFetchError(e) ||
!(e as SimpleFetchError).response ||
(e as SimpleFetchError).response?.status != 501
) {
throw e;
}

// if old API is not implemented, use the new one
const response = await simpleFetch<{ key: string }>(
this.url,
"/registration/v1beta1/tx-key"
);

this.consensusIoPubKey = new Uint8Array(
Buffer.from(response.data.key, "base64")
);
this.isNewApi = true;
}

return this.consensusIoPubKey;
}
Expand Down
21 changes: 21 additions & 0 deletions packages/background/src/secret-wasm/handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
GetTxEncryptionKeyMsg,
ReqeustEncryptMsg,
RequestDecryptMsg,
IsNewApiMsg,
} from "./messages";
import { SecretWasmService } from "./service";
import { PermissionInteractiveService } from "../permission-interactive";
Expand Down Expand Up @@ -40,6 +41,11 @@ export const getHandler: (
service,
permissionInteractionService
)(env, msg as GetTxEncryptionKeyMsg);
case IsNewApiMsg:
return handleIsNewApiMsg(service, permissionInteractionService)(
env,
msg as IsNewApiMsg
);
default:
throw new KeplrError("secret-wasm", 120, "Unknown msg type");
}
Expand All @@ -64,6 +70,21 @@ const handleGetPubkeyMsg: (
};
};

const handleIsNewApiMsg: (
service: SecretWasmService,
permissionInteractionService: PermissionInteractiveService
) => InternalHandler<IsNewApiMsg> = (service, permissionInteractionService) => {
return async (env, msg) => {
await permissionInteractionService.ensureEnabled(
env,
[msg.chainId],
msg.origin
);

return await service.isNewApi(msg.chainId);
};
};

const handleReqeustEncryptMsg: (
service: SecretWasmService,
permissionInteractionService: PermissionInteractiveService
Expand Down
2 changes: 2 additions & 0 deletions packages/background/src/secret-wasm/init.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
GetTxEncryptionKeyMsg,
ReqeustEncryptMsg,
RequestDecryptMsg,
IsNewApiMsg,
} from "./messages";
import { SecretWasmService } from "./service";
import { ROUTE } from "./constants";
Expand All @@ -19,6 +20,7 @@ export function init(
router.registerMessage(ReqeustEncryptMsg);
router.registerMessage(RequestDecryptMsg);
router.registerMessage(GetTxEncryptionKeyMsg);
router.registerMessage(IsNewApiMsg);

router.addHandler(ROUTE, getHandler(service, permissionInteractionService));
}
28 changes: 28 additions & 0 deletions packages/background/src/secret-wasm/messages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -145,3 +145,31 @@ export class GetTxEncryptionKeyMsg extends Message<Uint8Array> {
return GetTxEncryptionKeyMsg.type();
}
}

export class IsNewApiMsg extends Message<boolean> {
public static type() {
return "is-new-api-msg";
}

constructor(public readonly chainId: string) {
super();
}

validateBasic(): void {
if (!this.chainId) {
throw new KeplrError("secret-wasm", 100, "chain id not set");
}
}

override approveExternal(): boolean {
return true;
}

route(): string {
return ROUTE;
}

type(): string {
return IsNewApiMsg.type();
}
}
13 changes: 13 additions & 0 deletions packages/background/src/secret-wasm/service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,19 @@ export class SecretWasmService {
return utils.getTxEncryptionKey(nonce);
}

async isNewApi(chainId: string): Promise<boolean> {
const chainInfo = await this.chainsService.getChainInfoOrThrow(chainId);

// XXX: Keplr should generate the seed deterministically according to the account.
// Otherwise, it will lost the encryption/decryption key if Keplr is uninstalled or local storage is cleared.
// For now, use the signature of some string to generate the seed.
// It need to more research.
const seed = await this.getSeed(chainInfo);

const utils = this.getEnigmaUtils(chainInfo, seed);
return utils.isNewApi;
}

async encrypt(
chainId: string,
contractCodeHash: string,
Expand Down
2 changes: 1 addition & 1 deletion packages/proto-types/outputHash
Original file line number Diff line number Diff line change
@@ -1 +1 @@
47xVj6yH8GxPnu1BOIH1MiJVtlE6POLMYvtUZYTBu/5MPH+/VZKmDSx8zscGTLTJpxn9rxdR/+cPKXJdeaqXzulJEYlXTSU7x80PSUD7rlp2mWT0RYGFDIN+Fik5sFOv7Um1WRmAnzsEu+hDNatREyB47p1Gxms6JX0klLRyAyxUnUJRvDIjqQiAHvjtBGK0z5Fgtw08ei6MwIGQTf1GQHMO/FAQfd3uq8plIG5KNxinIvHEu7y1qZFBLB7UiMKcd8fWxfvYJA4IV73pCYbInRh3jcatX/QI80oBDMXBo9DCv5IaZQQs1G7JPcfzThPm
47xVj6yH8GxPnu1BOIH1MiJVtlE6POLMYvtUZYTBu/5MPH+/VZKmDSx8zscGTLTJpxn9rxdR/+cPKXJdeaqXzulJEYlXTSU7x80PSUD7rlp2mWT0RYGFDIN+Fik5sFOv7Um1WRmAnzsEu+hDNatREyB47p1Gxms6JX0klLRyAyxUnUJRvDIjqQiAHvjtBGK0z5Fgtw08ei6MwIGQTf1GQHMO/FAQfd3uq8plIG5KNxinIvHEViD2YjIK7cmuvNIFc5CdQK0lzAoIV73pCYbInRh3jcatX/QI80oBDMXBo9DCv5IaZQQs1G7JPcfzThPm
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
syntax = "proto3";
package secret.compute.v1beta1;

import "gogoproto/gogo.proto";
import "secret/compute/v1beta1/types.proto";

option go_package = "github.com/scrtlabs/SecretNetwork/x/compute/internal/types";

// GenesisState - genesis state of x/wasm
message GenesisState {
// Params params = 1 [(gogoproto.nullable) = false];
repeated Code codes = 2
[ (gogoproto.nullable) = false, (gogoproto.jsontag) = "codes,omitempty" ];
repeated Contract contracts = 3 [
(gogoproto.nullable) = false,
(gogoproto.jsontag) = "contracts,omitempty"
];
repeated Sequence sequences = 4 [
(gogoproto.nullable) = false,
(gogoproto.jsontag) = "sequences,omitempty"
];
}

// Code struct encompasses CodeInfo and CodeBytes
message Code {
uint64 code_id = 1 [ (gogoproto.customname) = "CodeID" ];
CodeInfo code_info = 2 [ (gogoproto.nullable) = false ];
bytes code_bytes = 3;
}

// Contract struct encompasses ContractAddress, ContractInfo, and ContractState
message Contract {
bytes contract_address = 1
[ (gogoproto.casttype) =
"github.com/cosmos/cosmos-sdk/types.AccAddress" ];
ContractInfo contract_info = 2 [ (gogoproto.nullable) = false ];
repeated Model contract_state = 3 [ (gogoproto.nullable) = false ];
ContractCustomInfo contract_custom_info = 4;
}

// Sequence id and value of a counter
message Sequence {
bytes id_key = 1 [ (gogoproto.customname) = "IDKey" ];
uint64 value = 2;
}
Loading

0 comments on commit 318c0db

Please sign in to comment.