Skip to content

Commit

Permalink
State changes + getTransactions fn (#16)
Browse files Browse the repository at this point in the history
* Process a batchStatus response correctly, since it was reorganized

* Update a list of smart transactions properly

* Use "smartTransactionsState", add a new "getTransactions" fn

* Update UTs to support the "smartTransactionsState" namespace
  • Loading branch information
dan437 authored Nov 4, 2021
1 parent f0d4bfc commit 796dacd
Show file tree
Hide file tree
Showing 2 changed files with 120 additions and 53 deletions.
81 changes: 53 additions & 28 deletions src/SmartTransactionsController.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ jest.mock('ethers', () => ({

getTransactionReceipt = jest.fn(() => ({ blockNumber: '123' }));

getTransaction = jest.fn();

getBlock = jest.fn();
},
},
Expand Down Expand Up @@ -224,10 +226,12 @@ describe('SmartTransactionsController', () => {

it('initializes with default state', () => {
expect(smartTransactionsController.state).toStrictEqual({
smartTransactions: {
[CHAIN_IDS.ETHEREUM]: [],
smartTransactionsState: {
smartTransactions: {
[CHAIN_IDS.ETHEREUM]: [],
},
userOptIn: undefined,
},
userOptIn: undefined,
});
});

Expand Down Expand Up @@ -286,11 +290,17 @@ describe('SmartTransactionsController', () => {
describe('setOptInState', () => {
it('sets optIn state', () => {
smartTransactionsController.setOptInState(true);
expect(smartTransactionsController.state.userOptIn).toBe(true);
expect(
smartTransactionsController.state.smartTransactionsState.userOptIn,
).toBe(true);
smartTransactionsController.setOptInState(false);
expect(smartTransactionsController.state.userOptIn).toBe(false);
expect(
smartTransactionsController.state.smartTransactionsState.userOptIn,
).toBe(false);
smartTransactionsController.setOptInState(undefined);
expect(smartTransactionsController.state.userOptIn).toBeUndefined();
expect(
smartTransactionsController.state.smartTransactionsState.userOptIn,
).toBeUndefined();
});
});

Expand Down Expand Up @@ -326,9 +336,8 @@ describe('SmartTransactionsController', () => {
});

expect(
smartTransactionsController.state.smartTransactions[
CHAIN_IDS.ETHEREUM
][0].uuid,
smartTransactionsController.state.smartTransactionsState
.smartTransactions[CHAIN_IDS.ETHEREUM][0].uuid,
).toStrictEqual('dP23W7c2kt4FK9TmXOkz1UM2F20');
});
});
Expand All @@ -342,34 +351,43 @@ describe('SmartTransactionsController', () => {
.reply(200, pendingBatchStatusApiResponse);
await smartTransactionsController.fetchSmartTransactionsStatus(uuids);
expect(smartTransactionsController.state).toStrictEqual({
smartTransactions: {
[CHAIN_IDS.ETHEREUM]: createStateAfterPending(),
smartTransactionsState: {
smartTransactions: {
[CHAIN_IDS.ETHEREUM]: createStateAfterPending(),
},
userOptIn: undefined,
},
userOptIn: undefined,
});
});

it('fetches a success status for a single smart transaction via batchStatus API', async () => {
const uuids = ['uuid2'];
const successBatchStatusApiResponse = createSuccessBatchStatusApiResponse();
smartTransactionsController.update({
smartTransactions: {
[CHAIN_IDS.ETHEREUM]: createStateAfterPending() as SmartTransaction[],
smartTransactionsState: {
...smartTransactionsController.state.smartTransactionsState,
smartTransactions: {
[CHAIN_IDS.ETHEREUM]: createStateAfterPending() as SmartTransaction[],
},
},
});

nock(API_BASE_URL)
.get(`/networks/${ethereumChainIdDec}/batchStatus?uuids=uuid2`)
.reply(200, successBatchStatusApiResponse);
await smartTransactionsController.fetchSmartTransactionsStatus(uuids);
expect(smartTransactionsController.state).toStrictEqual({
smartTransactions: {
[CHAIN_IDS.ETHEREUM]: [
...createStateAfterPending(),
...createStateAfterSuccess(),
],
expect(
smartTransactionsController.state.smartTransactionsState,
).toStrictEqual({
smartTransactionsState: {
smartTransactions: {
[CHAIN_IDS.ETHEREUM]: [
...createStateAfterPending(),
...createStateAfterSuccess(),
],
},
userOptIn: undefined,
},
userOptIn: undefined,
});
});
});
Expand All @@ -388,9 +406,13 @@ describe('SmartTransactionsController', () => {
describe('updateSmartTransaction', () => {
it('updates smart transaction based on uuid', () => {
const pendingStx = createStateAfterPending()[0];
const { smartTransactionsState } = smartTransactionsController.state;
smartTransactionsController.update({
smartTransactions: {
[CHAIN_IDS.ETHEREUM]: [pendingStx] as SmartTransaction[],
smartTransactionsState: {
...smartTransactionsState,
smartTransactions: {
[CHAIN_IDS.ETHEREUM]: [pendingStx] as SmartTransaction[],
},
},
});
const updateTransaction = {
Expand All @@ -402,21 +424,24 @@ describe('SmartTransactionsController', () => {
);

expect(
smartTransactionsController.state.smartTransactions[
CHAIN_IDS.ETHEREUM
][0].status,
smartTransactionsController.state.smartTransactionsState
.smartTransactions[CHAIN_IDS.ETHEREUM][0].status,
).toStrictEqual('test');
});

it('confirms a smart transaction that has status success', async () => {
const { smartTransactionsState } = smartTransactionsController.state;
const confirmSpy = jest.spyOn(
smartTransactionsController,
'confirmSmartTransaction',
);
const pendingStx = createStateAfterPending()[0];
smartTransactionsController.update({
smartTransactions: {
[CHAIN_IDS.ETHEREUM]: [pendingStx] as SmartTransaction[],
smartTransactionsState: {
...smartTransactionsState,
smartTransactions: {
[CHAIN_IDS.ETHEREUM]: [pendingStx] as SmartTransaction[],
},
},
});
const updateTransaction = {
Expand Down
92 changes: 67 additions & 25 deletions src/SmartTransactionsController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,10 @@ export interface SmartTransactionsControllerConfig extends BaseConfig {
}

export interface SmartTransactionsControllerState extends BaseState {
smartTransactions: Record<string, SmartTransaction[]>;
userOptIn: boolean | undefined;
smartTransactionsState: {
smartTransactions: Record<string, SmartTransaction[]>;
userOptIn: boolean | undefined;
};
}

export default class SmartTransactionsController extends BaseController<
Expand Down Expand Up @@ -106,8 +108,10 @@ export default class SmartTransactionsController extends BaseController<
};

this.defaultState = {
smartTransactions: {},
userOptIn: undefined,
smartTransactionsState: {
smartTransactions: {},
userOptIn: undefined,
},
};

this.nonceTracker = nonceTracker;
Expand All @@ -131,11 +135,16 @@ export default class SmartTransactionsController extends BaseController<

initializeSmartTransactionsForChainId() {
if (this.config.supportedChainIds.includes(this.config.chainId)) {
const { smartTransactionsState } = this.state;
this.update({
smartTransactions: {
...this.state.smartTransactions,
[this.config.chainId]:
this.state.smartTransactions[this.config.chainId] ?? [],
smartTransactionsState: {
...smartTransactionsState,
smartTransactions: {
...smartTransactionsState.smartTransactions,
[this.config.chainId]:
smartTransactionsState.smartTransactions[this.config.chainId] ??
[],
},
},
});
}
Expand All @@ -159,12 +168,18 @@ export default class SmartTransactionsController extends BaseController<
}

setOptInState(state: boolean | undefined): void {
this.update({ userOptIn: state });
this.update({
smartTransactionsState: {
...this.state.smartTransactionsState,
userOptIn: state,
},
});
}

updateSmartTransaction(smartTransaction: SmartTransaction): void {
const { chainId } = this.config;
const { smartTransactions } = this.state;
const { smartTransactionsState } = this.state;
const { smartTransactions } = smartTransactionsState;
const currentSmartTransactions = smartTransactions[chainId];
const currentIndex = currentSmartTransactions?.findIndex(
(st) => st.uuid === smartTransaction.uuid,
Expand All @@ -176,12 +191,15 @@ export default class SmartTransactionsController extends BaseController<
const history = [snapshot];
const historifiedSmartTransaction = { ...smartTransaction, history };
this.update({
smartTransactions: {
...this.state.smartTransactions,
[chainId]: [
...this.state.smartTransactions?.[chainId],
historifiedSmartTransaction,
],
smartTransactionsState: {
...smartTransactionsState,
smartTransactions: {
...smartTransactionsState.smartTransactions,
[chainId]: [
...smartTransactionsState.smartTransactions?.[chainId],
historifiedSmartTransaction,
],
},
},
});
return;
Expand All @@ -202,19 +220,24 @@ export default class SmartTransactionsController extends BaseController<
}

this.update({
smartTransactions: {
...this.state.smartTransactions,
[chainId]: this.state.smartTransactions[chainId].map((item, index) => {
return index === currentIndex
? { ...item, ...smartTransaction }
: item;
}),
smartTransactionsState: {
...smartTransactionsState,
smartTransactions: {
...smartTransactionsState.smartTransactions,
[chainId]: smartTransactionsState.smartTransactions[chainId].map(
(item, index) => {
return index === currentIndex
? { ...item, ...smartTransaction }
: item;
},
),
},
},
});
}

async updateSmartTransactions() {
const { smartTransactions } = this.state;
const { smartTransactions } = this.state.smartTransactionsState;
const { chainId } = this.config;

const currentSmartTransactions = smartTransactions?.[chainId];
Expand Down Expand Up @@ -333,7 +356,7 @@ export default class SmartTransactionsController extends BaseController<
nonceLock.releaseLock();
return {
...transaction,
nonce,
nonce: `0x${nonce.toString(16)}`,
};
}

Expand Down Expand Up @@ -446,4 +469,23 @@ export default class SmartTransactionsController extends BaseController<
this.configure({ interval }, false, false);
}
}

getTransactions({
addressFrom,
status,
}: {
addressFrom: string;
status: SmartTransactionStatuses;
}): SmartTransaction[] {
const { smartTransactions } = this.state.smartTransactionsState;
const { chainId } = this.config;
const currentSmartTransactions = smartTransactions?.[chainId];
if (!currentSmartTransactions || currentSmartTransactions.length === 0) {
return [];
}

return currentSmartTransactions.filter((stx) => {
return stx.status === status && stx.txParams?.from === addressFrom;
});
}
}

0 comments on commit 796dacd

Please sign in to comment.