Skip to content

Commit

Permalink
Added ArchivedAccountData for dealing with archived accounts
Browse files Browse the repository at this point in the history
  • Loading branch information
marcvelmer committed Dec 21, 2023
1 parent 20c865e commit 420bdf3
Show file tree
Hide file tree
Showing 5 changed files with 96 additions and 27 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]

### Added

- Added `ArchivedAccountData` for dealing with archived accounts and new `fetchAccount` function in client.

## [0.7.0] - 2023-12-13

### Changed
Expand Down
15 changes: 15 additions & 0 deletions src/api/account.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ enum AccountAPIMethods {
LIST = '/accounts/page',
NUM_ACCOUNTS = '/accounts/count',
INFO = '/accounts/{accountId}',
METADATA = '/accounts/{accountId}/metadata',
SET_INFO = '/accounts',
ELECTIONS = '/accounts/{accountId}/elections/page',
TRANSFERS = '/accounts/{accountId}/transfers/page',
Expand Down Expand Up @@ -150,6 +151,20 @@ export abstract class AccountAPI extends API {
.catch(this.isApiError);
}

/**
* Fetches the account metadata
*
* @param {string} url API endpoint URL
* @param {string} accountId The account we want the info from
* @returns {Promise<AccountMetadata>}
*/
public static metadata(url: string, accountId: string): Promise<AccountMetadata> {
return axios
.get<AccountMetadata>(url + AccountAPIMethods.METADATA.replace('{accountId}', accountId))
.then((response) => response.data)
.catch(this.isApiError);
}

/**
* Sets Account information
*
Expand Down
51 changes: 40 additions & 11 deletions src/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import {
AccountData,
AccountService,
AnonymousService,
ArchivedAccountData,
CensusProof,
CensusService,
ChainCircuits,
Expand Down Expand Up @@ -93,7 +94,7 @@ export type ClientOptions = {
* point.
*/
export class VocdoniSDKClient {
private accountData: AccountData | null = null;
private accountData: AccountData | ArchivedAccountData | null = null;
private election: UnpublishedElection | PublishedElection | null = null;

public censusService: CensusService;
Expand Down Expand Up @@ -168,9 +169,28 @@ export class VocdoniSDKClient {
* Fetches account information.
*
* @param {string} address The account address to fetch the information
* @returns {Promise<AccountData | ArchivedAccountData>}
*/
async fetchAccountInfo(address?: string): Promise<AccountData | ArchivedAccountData> {
if (!this.wallet && !address) {
throw Error('No account set');
} else if (address) {
this.accountData = await this.accountService.fetchAccountInfo(address);
} else {
this.accountData = await this.wallet
.getAddress()
.then((address) => this.accountService.fetchAccountInfo(address));
}
return this.accountData;
}

/**
* Fetches account.
*
* @param {string} address The account address to fetch the information
* @returns {Promise<AccountData>}
*/
async fetchAccountInfo(address?: string): Promise<AccountData> {
async fetchAccount(address?: string): Promise<AccountData> {
if (!this.wallet && !address) {
throw Error('No account set');
} else if (address) {
Expand All @@ -180,6 +200,15 @@ export class VocdoniSDKClient {
.getAddress()
.then((address) => this.accountService.fetchAccountInfo(address));
}

const isAccount = (account: AccountData | ArchivedAccountData): account is AccountData => {
return (account as AccountData).nonce !== undefined;
};

if (!isAccount(this.accountData)) {
throw Error('Account is archived');
}

return this.accountData;
}

Expand Down Expand Up @@ -321,7 +350,7 @@ export class VocdoniSDKClient {
invariant(account, 'No account');

const accountData = Promise.all([
this.fetchAccountInfo(),
this.fetchAccount(),
this.fetchChainId(),
this.fileService.calculateCID(JSON.stringify(account.generateMetadata())),
]).then((data) => AccountCore.generateUpdateAccountTransaction(data[0].address, data[0].nonce, account, data[2]));
Expand All @@ -345,7 +374,7 @@ export class VocdoniSDKClient {
return Promise.all([promAccountData, accountTx])
.then((accountInfo) => this.accountService.setInfo(accountInfo[1], accountInfo[0].metadata))
.then((txHash) => this.chainService.waitForTransaction(txHash))
.then(() => this.fetchAccountInfo());
.then(() => this.fetchAccount());
}

/**
Expand All @@ -370,7 +399,7 @@ export class VocdoniSDKClient {
...options,
};

return this.fetchAccountInfo().catch(() => {
return this.fetchAccount().catch(() => {
if (settings?.sik) {
return this.anonymousService.signSIKPayload(this.wallet).then((signedPayload) =>
this.createAccountInfo({
Expand Down Expand Up @@ -403,7 +432,7 @@ export class VocdoniSDKClient {
invariant(settings.to && isAddress(settings.to), 'No destination address given');
invariant(settings.amount && settings.amount > 0, 'No amount given');

return Promise.all([this.fetchAccountInfo(), settings.wallet.getAddress()])
return Promise.all([this.fetchAccount(), settings.wallet.getAddress()])
.then(([accountData, fromAddress]) => {
const transferTx = AccountCore.generateTransferTransaction(
accountData.nonce,
Expand All @@ -428,15 +457,15 @@ export class VocdoniSDKClient {
const faucet = faucetPackage
? Promise.resolve(faucetPackage)
: this.wallet.getAddress().then((address) => this.faucetService.fetchPayload(address));
return Promise.all([this.fetchAccountInfo(), faucet])
return Promise.all([this.fetchAccount(), faucet])
.then(([account, faucet]) => {
const faucetPackage = this.faucetService.parseFaucetPackage(faucet);
const collectFaucetTx = AccountCore.generateCollectFaucetTransaction(account.nonce, faucetPackage);
return this.accountService.signTransaction(collectFaucetTx.tx, collectFaucetTx.message, this.wallet);
})
.then((signedTx) => this.chainService.submitTx(signedTx))
.then((hash) => this.chainService.waitForTransaction(hash))
.then(() => this.fetchAccountInfo());
.then(() => this.fetchAccount());
}

/**
Expand Down Expand Up @@ -496,7 +525,7 @@ export class VocdoniSDKClient {
key: ElectionCreationSteps.CENSUS_CREATED,
};

const account = await this.fetchAccountInfo();
const account = await this.fetchAccount();
yield {
key: ElectionCreationSteps.GET_ACCOUNT_DATA,
};
Expand Down Expand Up @@ -603,7 +632,7 @@ export class VocdoniSDKClient {
if (!this.electionId && !electionId) {
throw Error('No election set');
}
return this.fetchAccountInfo()
return this.fetchAccount()
.then((accountData) => {
const setElectionStatusTx = ElectionCore.generateSetElectionStatusTransaction(
electionId ?? this.electionId,
Expand All @@ -628,7 +657,7 @@ export class VocdoniSDKClient {
if (!this.electionId && !electionId) {
throw Error('No election set');
}
return this.fetchAccountInfo()
return this.fetchAccount()
.then((accountData) => {
const setElectionCensusTx = ElectionCore.generateSetElectionCensusTransaction(
electionId ?? this.electionId,
Expand Down
47 changes: 33 additions & 14 deletions src/services/account.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,12 @@ export type AccountData = {
nonce: number;
electionIndex: number;
infoURL?: string;
sik?: string;
account: Account;
};

export type ArchivedAccountData = Pick<AccountData, 'address' | 'account'>;

export class AccountService extends Service implements AccountServiceProperties {
public chainService: ChainService;

Expand All @@ -50,21 +53,37 @@ export class AccountService extends Service implements AccountServiceProperties
* @param {string} address The account address to fetch the information
* @returns {Promise<AccountData>}
*/
async fetchAccountInfo(address: string): Promise<AccountData> {
async fetchAccountInfo(address: string): Promise<AccountData | ArchivedAccountData> {
invariant(this.url, 'No URL set');
return AccountAPI.info(this.url, address).then((accountInfo) => ({
account: Account.build({
languages: accountInfo.metadata?.languages,
name: accountInfo.metadata?.name,
description: accountInfo.metadata?.description,
feed: accountInfo.metadata?.newsFeed,
header: accountInfo.metadata?.media?.header,
avatar: accountInfo.metadata?.media?.avatar,
logo: accountInfo.metadata?.media?.logo,
meta: Object.entries(accountInfo.metadata?.meta ?? []).map(([key, value]) => ({ key, value })),
}),
...accountInfo,
}));
return AccountAPI.info(this.url, address)
.then((accountInfo) => ({
account: Account.build({
languages: accountInfo.metadata?.languages,
name: accountInfo.metadata?.name,
description: accountInfo.metadata?.description,
feed: accountInfo.metadata?.newsFeed,
header: accountInfo.metadata?.media?.header,
avatar: accountInfo.metadata?.media?.avatar,
logo: accountInfo.metadata?.media?.logo,
meta: Object.entries(accountInfo.metadata?.meta ?? []).map(([key, value]) => ({ key, value })),
}),
...accountInfo,
}))
.catch(() =>
AccountAPI.metadata(this.url, address).then((metadata) => ({
address,
account: Account.build({
languages: metadata?.languages,
name: metadata?.name,
description: metadata?.description,
feed: metadata?.newsFeed,
header: metadata?.media?.header,
avatar: metadata?.media?.avatar,
logo: metadata?.media?.logo,
meta: Object.entries(metadata?.meta ?? []).map(([key, value]) => ({ key, value })),
}),
}))
);
}

/**
Expand Down
4 changes: 2 additions & 2 deletions test/integration/account.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -143,9 +143,9 @@ describe('Account integration tests', () => {

await client
.sendTokens({ to: destinationAccount.address, amount: TOKENS_AMOUNT })
.then(() => client.fetchAccountInfo())
.then(() => client.fetchAccount())
.then((accountData) => expect(accountData.balance).toEqual(accountInfo.balance - TOKENS_AMOUNT - SEND_TX_COST))
.then(() => destinationClient.fetchAccountInfo())
.then(() => destinationClient.fetchAccount())
.then((destinationData) => expect(destinationData.balance).toEqual(destinationInfo.balance + TOKENS_AMOUNT));
}, 85000);
});

0 comments on commit 420bdf3

Please sign in to comment.