Skip to content

Commit 2902ec3

Browse files
committed
feat(wallet-backend): add walletAdmin.getClockNotifier()
1 parent 1b4a22b commit 2902ec3

File tree

3 files changed

+111
-22
lines changed

3 files changed

+111
-22
lines changed

packages/dapp-svelte-wallet/api/src/internal-types.js

+6-5
Original file line numberDiff line numberDiff line change
@@ -65,14 +65,15 @@
6565

6666
/**
6767
* @typedef {Object} PaymentRecord
68-
* @property {Issuer=} issuer
68+
* @property {RecordMetadata} meta
69+
* @property {Issuer} [issuer]
6970
* @property {Payment} payment
7071
* @property {Brand} brand
71-
* @property {'pending'|'deposited'|undefined} status
72+
* @property {'pending'|'deposited'} [status]
7273
* @property {PaymentActions} actions
73-
* @property {Amount=} lastAmount
74-
* @property {Amount=} depositedAmount
75-
* @property {string=} issuerBoardId
74+
* @property {Amount} [lastAmount]
75+
* @property {Amount} [depositedAmount]
76+
* @property {string} [issuerBoardId]
7677
*
7778
* @typedef {Object} PaymentActions
7879
* @property {(purseOrPetname?: (Purse | Petname)) => Promise<Value>} deposit

packages/dapp-svelte-wallet/api/src/lib-wallet.js

+93-17
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,10 @@ import '@agoric/zoe/exported.js';
3535
import './internal-types.js';
3636
import './types.js';
3737

38+
// The localTimerService uses a resolution of 1 millisecond.
39+
const LOCAL_TIMER_NO_DELAY = 0n;
40+
const LOCAL_TIMER_ONE_SECOND = 1000n;
41+
3842
// does nothing
3943
const noActionStateChangeHandler = _newState => {};
4044

@@ -48,6 +52,45 @@ const cmp = (a, b) => {
4852
return -1;
4953
};
5054

55+
/**
56+
* @param {ERef<TimerService> | undefined} timerService
57+
* @param {(stamp: bigint) => void} updateClock
58+
* @param {bigint} timerDelay
59+
* @param {bigint} timerInterval
60+
* @returns {Promise<void>}
61+
*/
62+
const initializeClock = async (
63+
timerService,
64+
updateClock,
65+
timerDelay,
66+
timerInterval,
67+
) => {
68+
if (!timerService) {
69+
return;
70+
}
71+
72+
// Get a baseline.
73+
const time0 = await E(timerService).getCurrentTimestamp();
74+
updateClock(time0);
75+
76+
const notifier = await E(timerService).makeNotifier(
77+
timerDelay,
78+
timerInterval,
79+
);
80+
81+
// Subscribe to future updates.
82+
observeNotifier(notifier, {
83+
updateState: updateClock,
84+
}).catch(e => {
85+
console.error(
86+
`Observing localTimerService`,
87+
timerService,
88+
'failed with:',
89+
e,
90+
);
91+
});
92+
};
93+
5194
/**
5295
* @typedef {Object} MakeWalletParams
5396
* @property {ERef<ZoeService>} zoe
@@ -75,33 +118,37 @@ export function makeWallet({
75118
*
76119
* @type {number | undefined}
77120
*/
78-
let nowMs;
79-
80-
// Subscribe to the timer service to update our stamp.
81-
if (localTimerService) {
82-
observeNotifier(E(localTimerService).makeNotifier(0n, 1000n), {
83-
updateState(bigStamp) {
84-
// We need to convert the bigint to a number (for easy Javascript date math).
85-
nowMs = parseInt(`${bigStamp}`, 10);
86-
},
87-
});
88-
}
89-
121+
let nowStamp;
90122
let lastSequence = 0;
123+
124+
/**
125+
* Add or update a record's `meta` property. Note that the Stamps are in
126+
* milliseconds since the epoch, and they are only added if this backend has
127+
* been supplied a `localTimerService`.
128+
*
129+
* The `sequence` is guaranteed to be monotonically increasing, even if this
130+
* backend doesn't have a `localTimerService`, or the stamp has not yet
131+
* increased.
132+
*
133+
* @template {Record<string, any>} T
134+
* @param {T} record what to add metadata to
135+
* @returns {T & { meta: T['meta'] & RecordMetadata }}
136+
*/
91137
const addMeta = record => {
92138
const { meta: oldMeta = {} } = record;
139+
/** @type {Record<string, any> & T['meta']} */
93140
const meta = { ...oldMeta };
94141
if (!meta.sequence) {
95142
// Add a sequence number to the record.
96143
lastSequence += 1;
97144
meta.sequence = lastSequence;
98145
}
99-
if (nowMs !== undefined) {
146+
if (nowStamp !== undefined) {
100147
if (!meta.creationStamp) {
101148
// Set the creationStamp to be right now.
102-
meta.creationStamp = nowMs;
149+
meta.creationStamp = nowStamp;
103150
}
104-
meta.updatedStamp = nowMs;
151+
meta.updatedStamp = nowStamp;
105152
}
106153
return { ...record, meta };
107154
};
@@ -562,7 +609,7 @@ export function makeWallet({
562609

563610
const { inviteP, purseKeywordRecord, proposal } = await compiledOfferP;
564611

565-
// Track from whence our the payment came.
612+
// Track from whence our payment came.
566613
/** @type {Map<Payment, Purse>} */
567614
const paymentToPurse = new Map();
568615

@@ -1576,6 +1623,8 @@ export function makeWallet({
15761623
return offerResult.uiNotifier;
15771624
}
15781625

1626+
const { notifier: clockNotifier, updater: clockUpdater } = makeNotifierKit();
1627+
15791628
const wallet = Far('wallet', {
15801629
saveOfferResult,
15811630
getOfferResult,
@@ -1671,9 +1720,32 @@ export function makeWallet({
16711720
);
16721721
return E(namesByAddress).lookup(...path);
16731722
},
1723+
getClockNotifier: () => clockNotifier,
16741724
});
16751725

1726+
const updateNowStamp = bigStamp => {
1727+
// We convert the milliseconds from a bigint to a number (for easy
1728+
// Javascript date math).
1729+
const nextStamp = parseInt(`${bigStamp}`, 10);
1730+
1731+
if (nowStamp && nowStamp >= nextStamp) {
1732+
// Don't make an unnecessary update.
1733+
return;
1734+
}
1735+
1736+
nowStamp = nextStamp;
1737+
clockUpdater.updateState(nowStamp);
1738+
};
1739+
16761740
const initialize = async () => {
1741+
// Subscribe to the timer service to update our stamp.
1742+
await initializeClock(
1743+
localTimerService,
1744+
updateNowStamp,
1745+
LOCAL_TIMER_NO_DELAY,
1746+
LOCAL_TIMER_ONE_SECOND,
1747+
);
1748+
16771749
// Allow people to send us payments.
16781750
const selfDepositFacet = Far('contact', {
16791751
receive(payment) {
@@ -1743,5 +1815,9 @@ export function makeWallet({
17431815
feePurse,
17441816
);
17451817
};
1746-
return { admin: wallet, initialized: initialize(), importBankAssets };
1818+
return {
1819+
admin: wallet,
1820+
initialized: initialize(),
1821+
importBankAssets,
1822+
};
17471823
}

packages/dapp-svelte-wallet/api/src/types.js

+12
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,18 @@
8585
* Get the petnames for the brands that are passed in
8686
*/
8787

88+
/**
89+
* @typedef {Object} RecordMetadata
90+
* @property {number} sequence a monotonically increasing number to allow
91+
* total ordering between records.
92+
* @property {number} [creationStamp] the approximate time at which the record
93+
* was created in milliseconds since the epoch; `undefined` if there is no
94+
* timer source
95+
* @property {number} [updatedStamp] the approximate time at which the record
96+
* was last updated in milliseconds since the epoch; `undefined` if there is
97+
* no timer source
98+
*/
99+
88100
/**
89101
* @typedef {Object} PursesJSONState
90102
* @property {Brand} brand

0 commit comments

Comments
 (0)