Skip to content

Commit 8084a26

Browse files
feat: cleanup superhero id service code
1 parent a0ae47c commit 8084a26

File tree

5 files changed

+52
-40
lines changed

5 files changed

+52
-40
lines changed

src/composables/superheroId.ts

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ export function useSuperheroId(): {
2323
refreshHasSuperheroId: () => Promise<void>;
2424
syncAddressBook: (json: string) => Promise<void>;
2525
loadAddressBook: () => Promise<void>;
26+
deployContract: () => Promise<string>;
2627
} { // eslint-disable-line
2728
const { aeAccounts } = useAccounts();
2829
const { getAeSdk } = useAeSdk();
@@ -34,13 +35,21 @@ export function useSuperheroId(): {
3435

3536
const svcRef = superheroSvcRef as unknown as Ref<SuperheroIDService | null>;
3637

38+
function getService(): SuperheroIDService {
39+
if (!(superheroSvcRef.value instanceof SuperheroIDService)) {
40+
superheroSvcRef.value = new SuperheroIDService();
41+
}
42+
// TypeScript: assert concrete class
43+
return superheroSvcRef.value as SuperheroIDService;
44+
}
45+
3746
async function refreshHasSuperheroId(): Promise<void> {
3847
const addr = firstAeAddress.value;
3948
if (!addr) {
4049
hasSuperheroIdRef.value = false;
4150
return;
4251
}
43-
const svc = superheroSvcRef.value || new SuperheroIDService();
52+
const svc = getService();
4453
try {
4554
hasSuperheroIdRef.value = await svc.hasId();
4655
} catch {
@@ -51,8 +60,7 @@ export function useSuperheroId(): {
5160
async function syncAddressBook(json: string): Promise<void> {
5261
const addr = firstAeAddress.value;
5362
if (!addr) throw new Error('No æternity account');
54-
if (!superheroSvcRef.value) throw new Error('Connect Superhero ID first');
55-
const svc = superheroSvcRef.value;
63+
const svc = getService();
5664
const txBase64 = await svc.buildSetIdTx(json) as Encoded.Transaction;
5765
const tx = unpackTx(txBase64) as any;
5866
await openModal(MODAL_CONFIRM_TRANSACTION_SIGN, {
@@ -72,14 +80,21 @@ export function useSuperheroId(): {
7280
async function loadAddressBook() {
7381
const addr = firstAeAddress.value;
7482
if (!addr) throw new Error('No æternity account');
75-
const svc = superheroSvcRef.value || new SuperheroIDService();
83+
const svc = getService();
7684
const val = await svc.getId();
7785
hasSuperheroIdRef.value = !!val;
7886
if (val) {
7987
addAddressBookEntriesFromJson(val, false);
8088
}
8189
}
8290

91+
async function deployContract(): Promise<string> {
92+
const svc = getService();
93+
const res = await fetch('/contracts/SuperheroIds.aes');
94+
const source = await res.text();
95+
return svc.deployFromSource(source);
96+
}
97+
8398
// Re-init on network change if an AE account exists
8499
const { onNetworkChange } = useNetworks();
85100
onNetworkChange(async () => {
@@ -91,7 +106,6 @@ export function useSuperheroId(): {
91106
() => firstAeAddress.value,
92107
async (addr) => {
93108
if (addr) {
94-
if (!superheroSvcRef.value) superheroSvcRef.value = new SuperheroIDService();
95109
await refreshHasSuperheroId();
96110
} else {
97111
superheroSvcRef.value = null;
@@ -107,5 +121,6 @@ export function useSuperheroId(): {
107121
refreshHasSuperheroId,
108122
syncAddressBook,
109123
loadAddressBook,
124+
deployContract,
110125
};
111126
}

src/popup/locales/en.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -749,6 +749,9 @@
749749
"addressBook": "Address Book",
750750
"own": "Own",
751751
"recent": "Recent"
752+
},
753+
"superheroId": {
754+
"synced": "Address Book Sync with SH ID completed"
752755
}
753756
},
754757
"secureLogin": {

src/popup/pages/AddressBook.vue

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,9 +84,8 @@ export default defineComponent({
8484
const addr = aeAccounts.value?.[0]?.address as `ak_${string}`;
8585
if (!addr) throw new Error('No æternity account');
8686
await syncAddressBook(JSON.stringify(addressBook.value));
87-
openDefaultModal({ title: t('dashboard.superheroId.title'), msg: t('pages.addressBook.export.title') });
87+
openDefaultModal({ title: t('dashboard.superheroId.title'), msg: t('pages.addressBook.superheroId.synced') });
8888
} catch (e) {
89-
openDefaultModal({ title: t('dashboard.superheroId.title'), msg: t('common.connectionFailed') });
9089
handleUnknownError(e);
9190
} finally {
9291
isSyncing.value = false;

src/popup/pages/Dashboard.vue

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -192,7 +192,7 @@ export default defineComponent({
192192
const { multisigAccounts } = useMultisigAccounts();
193193
const { addressBook } = useAddressBook();
194194
const {
195-
superheroSvc,
195+
deployContract,
196196
hasSuperheroId,
197197
syncAddressBook,
198198
loadAddressBook,
@@ -228,15 +228,9 @@ export default defineComponent({
228228
pageIsActive.value = false;
229229
});
230230
231-
const connectedContractId = ref<string | null>(null);
232-
233231
async function onDeployContract() {
234232
try {
235-
const res = await fetch('/contracts/SuperheroIds.aes');
236-
const source = await res.text();
237-
const svc = superheroSvc.value!;
238-
const ct = await svc.deployFromSource(source);
239-
connectedContractId.value = ct;
233+
const ct = await deployContract();
240234
openDefaultModal({ title: t('dashboard.superheroId.title'), msg: t('dashboard.superheroId.deployedMsg', { ct }) });
241235
} catch (e) {
242236
openDefaultModal({ title: t('dashboard.superheroId.title'), msg: t('dashboard.superheroId.deployFailed') });

src/protocols/aeternity/libs/SuperheroIDService.ts

Lines changed: 26 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import {
22
Contract,
3+
ContractMethodsBase,
34
Encoded,
45
Tag,
56
} from '@aeternity/aepp-sdk';
@@ -11,25 +12,27 @@ import { useAccounts } from '@/composables/accounts';
1112
import { encrypt, decrypt, importAesKeyFromSecret } from '@/utils/crypto';
1213
import type { IAccount } from '@/types';
1314

14-
export type SuperheroIdsContract = Contract<{
15-
set_id: (id: string) => Promise<void>;
16-
get_id: () => Promise<{ decodedResult: string | undefined }>;
17-
has_id: () => Promise<{ decodedResult: boolean }>;
18-
}>;
15+
interface SuperheroIdsContractMethods extends ContractMethodsBase {
16+
set_id: (id: string) => void;
17+
get_id: () => string | undefined;
18+
has_id: () => boolean;
19+
}
20+
21+
export type SuperheroIdsContract = Contract<SuperheroIdsContractMethods>;
1922

2023
export class SuperheroIDService {
21-
private contractId: Encoded.ContractAddress = 'ct_kaUS1K6qFXn2wP2phR26WLWXEKu5YsgA2gq4RWvkB69KY2gYF';
24+
private contractId = 'ct_kaUS1K6qFXn2wP2phR26WLWXEKu5YsgA2gq4RWvkB69KY2gYF' as const;
2225

2326
private async getContractInstance(options?: Partial<ContractInitializeOptions>):
2427
Promise<SuperheroIdsContract> {
2528
const { getAeSdk } = useAeSdk();
2629
const aeSdk = await getAeSdk();
27-
return Contract.initialize({
30+
return Contract.initialize<SuperheroIdsContractMethods>({
2831
...aeSdk.getContext(),
2932
...options,
30-
aci: SuperheroIdsACI as any,
33+
aci: SuperheroIdsACI,
3134
address: this.contractId,
32-
}) as unknown as SuperheroIdsContract;
35+
});
3336
}
3437

3538
private static getCallerAccount(): IAccount {
@@ -45,8 +48,7 @@ export class SuperheroIDService {
4548
if (!account?.secretKey) throw new Error('Missing secret key for encryption');
4649
const key = await importAesKeyFromSecret(account.secretKey);
4750
const ciphertext = await encrypt(key, id);
48-
await (contract as any)
49-
.set_id(ciphertext, { fromAccount: account.address as Encoded.AccountAddress });
51+
await contract.set_id(ciphertext);
5052
}
5153

5254
async getId(): Promise<string | undefined> {
@@ -77,47 +79,46 @@ export class SuperheroIDService {
7779
if (!account?.secretKey) throw new Error('Missing secret key for encryption');
7880
const key = await importAesKeyFromSecret(account.secretKey);
7981
const ciphertext = await encrypt(key, id);
80-
const gasLimit = await (contract as any)._estimateGas('set_id', [ciphertext], {
82+
const gasLimit = await contract._estimateGas('set_id', [ciphertext], {
8183
senderId: account.address as Encoded.AccountAddress,
8284
});
83-
const callData = (contract as any)._calldata.encode((contract as any)._name, 'set_id', [ciphertext]);
84-
const built = await aeSdk.buildTx({
85+
const callData = contract._calldata.encode(contract._name, 'set_id', [ciphertext]);
86+
return aeSdk.buildTx({
8587
tag: Tag.ContractCallTx,
8688
callerId: account.address as Encoded.AccountAddress,
87-
contractId: this.contractId!,
89+
contractId: this.contractId,
8890
abiVersion: 3,
8991
amount: 0,
9092
callData,
9193
gasLimit,
92-
} as any);
93-
return built;
94+
});
9495
}
9596

9697
async deployContract(bytecode: Encoded.ContractBytearray): Promise<Encoded.ContractAddress> {
9798
const { getAeSdk } = useAeSdk();
9899
const aeSdk = await getAeSdk();
99-
const instance = await Contract.initialize({
100+
const instance = await Contract.initialize<SuperheroIdsContract>({
100101
...aeSdk.getContext(),
101-
aci: SuperheroIdsACI as any,
102+
aci: SuperheroIdsACI,
102103
bytecode,
103-
}) as any;
104+
});
104105

105106
await instance.init();
106-
const address = instance.$options.address as Encoded.ContractAddress;
107+
const { address } = instance.$options;
107108
this.contractId = address;
108109
return address;
109110
}
110111

111112
async deployFromSource(sourceCode: string): Promise<Encoded.ContractAddress> {
112113
const { getAeSdk } = useAeSdk();
113114
const aeSdk = await getAeSdk();
114-
const instance = await Contract.initialize({
115+
const instance = await Contract.initialize<SuperheroIdsContract>({
115116
...aeSdk.getContext(),
116-
aci: SuperheroIdsACI as any,
117+
aci: SuperheroIdsACI,
117118
sourceCode,
118-
}) as any;
119+
});
119120
await instance.init();
120-
const address = instance.$options.address as Encoded.ContractAddress;
121+
const { address } = instance.$options;
121122
this.contractId = address;
122123
return address;
123124
}

0 commit comments

Comments
 (0)