on master help sign in
Merge pull request #835 from willbach/l1-pending-tx
29d187dWill Galebach
src/components/L2/Headers/L2PointHeader.scss+11
@@ -12,6 +12,17 @@
12 margin-right: 8px;
12 margin-right: 8px;
13 }
13 }
14
14
15+ .l2-spawn {
16+ border-radius: $medium-border-radius;
17+ color: white;
18+ background-color: black;
19+ text-align: center;
20+ height: 24px;
21+ padding: 8px 7px 0;
22+ font-size: 14px;
23+ margin-right: 4px;
24+ }
25+
15 .dropdown {
26 .dropdown {
16 border-radius: $medium-border-radius;
27 border-radius: $medium-border-radius;
17 background-color: $washed-gray;
28 background-color: $washed-gray;
src/components/L2/Headers/L2PointHeader.tsx+2
@@ -83,6 +83,8 @@ const L2PointHeader = ({
83 {point.value > -1 && (
83 {point.value > -1 && (
84 <LayerIndicator size="lg" layer={point.layer} className="header" />
84 <LayerIndicator size="lg" layer={point.layer} className="header" />
85 )}
85 )}
86+ {/* uncomment for L2 spawn badge */}
87+ {/* {point.isL1 && point.isL2Spawn && <Box className="l2-spawn">L2 Spawn</Box>} */}
86 </Row>
88 </Row>
87 <Row className="info">
89 <Row className="info">
88 {renderInviteButton()}
90 {renderInviteButton()}
src/components/L2/PendingTransaction.scssnew file+64
@@ -0,0 +1,64 @@
1+@import 'style/shared/variables.scss';
2+
3+.pending-transaction {
4+ font-size: 14px;
5+ padding: 8px;
6+ border: 1px solid $light-gray;
7+ border-radius: $large-border-radius;
8+ margin-bottom: 16px;
9+
10+ .title-row {
11+ display: flex;
12+ flex-direction: row;
13+ justify-content: space-between;
14+ align-items: center;
15+ margin-bottom: 4px;
16+
17+ .title {
18+ font-weight: 600;
19+ }
20+
21+ .hash {
22+ color: $dark-gray;
23+
24+ svg {
25+ height: 18px;
26+ width: 18px;
27+ margin-bottom: -4px;
28+ -ms-transform:rotate(315deg); /* IE9 */
29+ -moz-transform: rotate(315deg); /* FF3.5/3.6 */
30+ -o-transform: rotate(315deg); /* Opera 10.5 */
31+ -webkit-transform: rotate(315deg); /* Saf3.1+ */
32+ transform: rotate(315deg); /* Newer browsers */
33+
34+ path {
35+ fill: $dark-gray;
36+ }
37+ }
38+ }
39+
40+ .rollup-timer {
41+ background-color: $rollup-yellow;
42+ padding: 4px 8px;
43+ width: 112px;
44+ border-radius: $medium-border-radius;
45+ display: flex;
46+ flex-direction: row;
47+ justify-content: center;
48+ align-items: center;
49+
50+ svg {
51+ height: 14px;
52+ width: 14px;
53+ margin-right: 4px;
54+ }
55+ }
56+ }
57+
58+ .info-row {
59+ display: flex;
60+ flex-direction: row;
61+ justify-content: space-between;
62+ align-items: center;
63+ }
64+}
src/components/L2/PendingTransaction.tsxnew file+89
@@ -0,0 +1,89 @@
1+import { Box, Row, Icon } from '@tlon/indigo-react';
2+import { L1TxnType } from 'lib/types/PendingL1Transaction';
3+import { useExploreTxUrl } from 'lib/explorer';
4+import LayerIndicator from './LayerIndicator';
5+
6+import './PendingTransaction.scss';
7+
8+export const getPendingTitle = (type?: string) =>
9+ type === 'set-management-proxy'
10+ ? 'Management Address Changed'
11+ : type === 'configure-keys'
12+ ? 'Network Keys Configured'
13+ : type === 'transfer-point'
14+ ? 'Point Transfered'
15+ : type === 'set-transfer-proxy'
16+ ? 'Transfer Proxy Changed'
17+ : type === 'set-spawn-proxy'
18+ ? 'Spawn Proxy Changed'
19+ : type === 'escape'
20+ ? 'Change Sponsor'
21+ : type === 'cancel-escape'
22+ ? 'Cancel Escape'
23+ : type === 'adopt'
24+ ? 'Accept Sponsorship'
25+ : type === 'reject'
26+ ? 'Reject Sponsorship'
27+ : type === 'detach'
28+ ? 'Detach Sponsee'
29+ : '';
30+
31+export const getPendingL1Title = (type?: L1TxnType) =>
32+ type === L1TxnType.setNetworkKeys
33+ ? 'Network Keys Configured'
34+ : type === L1TxnType.managementProxy
35+ ? 'Management Address Changed'
36+ : type === L1TxnType.transferProxy
37+ ? 'Transfer Proxy Changed'
38+ : type === L1TxnType.spawnProxy
39+ ? 'Spawn Proxy Changed'
40+ : type === L1TxnType.spawnPoint
41+ ? 'Spawn Point'
42+ : type === L1TxnType.acceptTransfer
43+ ? 'Accept Transfer'
44+ : type === L1TxnType.migrate
45+ ? 'Migrate to Layer 2'
46+ : type === L1TxnType.migrateSpawn
47+ ? 'Set Spawn Proxy to Layer 2'
48+ : '';
49+
50+interface Props {
51+ title: string;
52+ nextRoll?: string;
53+ hash?: string;
54+ layer: 1 | 2;
55+}
56+
57+const PendingTransactionComponent: React.FC<Props> = ({
58+ title,
59+ nextRoll,
60+ hash,
61+ layer,
62+}) => {
63+ const txHash = useExploreTxUrl(hash);
64+
65+ return (
66+ <Box className="pending-transaction">
67+ <Row className="title-row">
68+ <Box className="title">{title}</Box>
69+ {hash ? (
70+ <a className="hash" href={txHash} rel="noreferrer" target="_blank">
71+ Etherscan
72+ <Icon className="arrow" icon="ArrowEast" />
73+ </a>
74+ ) : (
75+ <Box className="rollup-timer">
76+ <Icon icon="Clock" />
77+ {nextRoll}
78+ </Box>
79+ )}
80+ </Row>
81+ <Row className="info-row">
82+ <LayerIndicator layer={layer} size="sm" />
83+ <Box className="date"></Box>
84+ </Row>
85+ </Box>
86+ );
87+};
88+
89+export default PendingTransactionComponent;
src/components/L2/PermissionIndicator.scssnew file+15
@@ -0,0 +1,15 @@
1+@import 'style/shared/variables.scss';
2+
3+.permission-indicator {
4+ position: absolute;
5+ top: 4px;
6+ right: 4px;
7+ height: 16px;
8+ line-height: 16px;
9+ font-size: 10px;
10+ vertical-align: middle;
11+ border-radius: $medium-border-radius;
12+ color: white;
13+ background-color: $dark-gray;
14+ padding: 0px 4px;
15+}
src/components/L2/PermissionIndicator.tsxnew file+35
@@ -0,0 +1,35 @@
1+import React from 'react';
2+import { Box } from '@tlon/indigo-react';
3+import { PermissionLevel, shouldDisplayPermissionLevel } from 'lib/types/Point';
4+
5+import './PermissionIndicator.scss';
6+
7+export interface PermissionIndicatorProps {
8+ permission: PermissionLevel;
9+ size?: 'sm' | 'smt' | 'md' | 'lg';
10+ className?: string;
11+ selected?: boolean;
12+}
13+
14+const permissionText = {
15+ own: 'OWN',
16+ manage: 'MGMT',
17+ spawn: 'SPWN',
18+ vote: 'VOTE',
19+ transfer: 'TSFR',
20+};
21+
22+const PermissionIndicator = ({
23+ permission,
24+ className = '',
25+}: PermissionIndicatorProps) => {
26+ const classes = `permission-indicator ${permission} ${className}`;
27+
28+ if (!permission || !shouldDisplayPermissionLevel(permission)) {
29+ return null;
30+ }
31+
32+ return <Box className={classes}>{permissionText[permission]}</Box>;
33+};
34+
35+export default PermissionIndicator;
src/components/L2/PointList.tsxnew file+65
@@ -0,0 +1,65 @@
1+import React from 'react';
2+import { Just } from 'folktale/maybe';
3+
4+import { useHistory } from 'store/history';
5+import { usePointCursor } from 'store/pointCursor';
6+import Point from 'lib/types/Point';
7+
8+import { Grid, Flex } from 'indigo-react';
9+import Passport from 'components/Passport';
10+import PermissionIndicator from './PermissionIndicator';
11+
12+interface PointListProps {
13+ points: Point[];
14+ className?: string;
15+ actions?: (point: Point, i: number) => React.Component;
16+ locked?: boolean;
17+ processing?: boolean;
18+}
19+
20+const PointList: React.FC<PointListProps> = function({
21+ points,
22+ className,
23+ actions,
24+ locked = false,
25+ processing = false,
26+ ...rest
27+}) {
28+ const { setPointCursor }: any = usePointCursor();
29+ const { push, names }: any = useHistory();
30+
31+ return (
32+ <Grid gap={4} className={className}>
33+ {points.map((point, i) => (
34+ <Grid.Item
35+ key={point.value}
36+ className={`full fourth-${(i % 4) + 1}-md fourth-${(i % 4) + 1}-lg`}>
37+ <Flex col className="rel">
38+ <Passport.Mini
39+ locked={locked}
40+ processing={processing}
41+ point={point.value}
42+ onClick={
43+ locked || processing
44+ ? undefined
45+ : () => {
46+ setPointCursor(Just(point.value));
47+ push(names.POINT);
48+ }
49+ }
50+ {...rest}
51+ />
52+ {actions && (
53+ <Flex.Item className="mt2">{actions(point, i)}</Flex.Item>
54+ )}
55+ {!locked && (
56+ <PermissionIndicator permission={point.permissionLevel} />
57+ )}
58+ </Flex>
59+ </Grid.Item>
60+ ))}
61+ </Grid>
62+ );
63+};
64+
65+export default PointList;
src/lib/getSuggestedGasPrice.js+18−8
@@ -31,7 +31,7 @@ export default async function getSuggestedGasPrice(networkType) {
31 case NETWORK_TYPES.LOCAL:
31 case NETWORK_TYPES.LOCAL:
32 default:
32 default:
33 try {
33 try {
34− const response = await fetch(
34+ const etherscanGas = await fetch(
35 'https://api.etherscan.io/api' +
35 'https://api.etherscan.io/api' +
36 '?module=gastracker' +
36 '?module=gastracker' +
37 '&action=gasoracle' +
37 '&action=gasoracle' +
@@ -42,20 +42,30 @@ export default async function getSuggestedGasPrice(networkType) {
42 }
42 }
43 );
43 );
44
44
45− const json = await response.json();
45+ const ethgasstationGas = await fetch(
46+ 'https://ethgasstation.info/json/ethgasAPI.json',
47+ {
48+ method: 'GET',
49+ cache: 'no-cache',
50+ }
51+ );
52+
53+ const etherscanGasJson = await etherscanGas.json();
54+
55+ const ethgasstationGasJson = await ethgasstationGas.json();
46
56
47 return {
57 return {
48 fast: {
58 fast: {
49− price: minGas(json.fast),
59+ price: minGas(etherscanGasJson.result.FastGasPrice),
50− wait: formatWait(json.fastWait),
60+ wait: formatWait(ethgasstationGasJson.fastWait),
51 },
61 },
52 average: {
62 average: {
53− price: minGas(json.average),
63+ price: minGas(etherscanGasJson.result.ProposeGasPrice),
54− wait: formatWait(json.avgWait),
64+ wait: formatWait(ethgasstationGasJson.avgWait),
55 },
65 },
56 low: {
66 low: {
57− price: minGas(json.safeLow),
67+ price: minGas(etherscanGasJson.result.SafeGasPrice),
58− wait: formatWait(json.safeLowWait),
68+ wait: formatWait(ethgasstationGasJson.safeLowWait),
59 },
69 },
60 };
70 };
61 } catch (e) {
71 } catch (e) {
src/lib/proxy.js+17
@@ -1,3 +1,5 @@
1+import { L1TxnType } from './types/PendingL1Transaction';
2+
1export const PROXY_TYPE = {
3export const PROXY_TYPE = {
2 MANAGEMENT: 'MANAGEMENT',
4 MANAGEMENT: 'MANAGEMENT',
3 SPAWN: 'SPAWN',
5 SPAWN: 'SPAWN',
@@ -20,6 +22,21 @@ export const proxyTypeToHuman = proxyType => {
20 }
22 }
21};
23};
22
24
25+export const proxyTypeToL1TxnType = proxyType => {
26+ switch (proxyType) {
27+ case PROXY_TYPE.MANAGEMENT:
28+ return L1TxnType.managementProxy;
29+ case PROXY_TYPE.SPAWN:
30+ return L1TxnType.spawnProxy;
31+ case PROXY_TYPE.TRANSFER:
32+ return L1TxnType.transferProxy;
33+ case PROXY_TYPE.VOTING:
34+ return L1TxnType.votingProxy;
35+ default:
36+ throw new Error(`Unknown proxyType: ${proxyType}`);
37+ }
38+};
39+
23export const proxyTypeToHumanDescription = proxyType => {
40export const proxyTypeToHumanDescription = proxyType => {
24 switch (proxyType) {
41 switch (proxyType) {
25 case PROXY_TYPE.MANAGEMENT:
42 case PROXY_TYPE.MANAGEMENT:
src/lib/router.js+1−1
@@ -20,7 +20,7 @@ import IssueChild from 'views/Point/IssueChild';
20
20
21import PartySetPoolSize from 'views/Party/PartySetPoolSize';
21import PartySetPoolSize from 'views/Party/PartySetPoolSize';
22import InviteCohort from 'views/Invite/Cohort';
22import InviteCohort from 'views/Invite/Cohort';
23−import AcceptTransfer from 'views/AcceptTransfer';
23+import AcceptTransfer from 'views/AcceptTransfer.tsx';
24import CancelTransfer from 'views/CancelTransfer';
24import CancelTransfer from 'views/CancelTransfer';
25import Bitcoin from 'views/Bitcoin/Bitcoin';
25import Bitcoin from 'views/Bitcoin/Bitcoin';
26import Xpub from 'views/Bitcoin/Xpub';
26import Xpub from 'views/Bitcoin/Xpub';
src/lib/types/PendingL1Transaction.tsnew file+22
@@ -0,0 +1,22 @@
1+export enum L1TxnType {
2+ migrate = 'migrate',
3+ migrateSpawn = 'migrateSpawn',
4+ spawnProxy = 'spawnProxy',
5+ managementProxy = 'managementProxy',
6+ transferProxy = 'transferProxy',
7+ votingProxy = 'votingProxy',
8+ acceptTransfer = 'acceptTransfer',
9+ spawnPoint = 'spawnPoint',
10+ setNetworkKeys = 'setNetworkKeys',
11+}
12+
13+export interface PendingL1Txn {
14+ id: string;
15+ point: number;
16+ type: L1TxnType;
17+ hash: string;
18+}
19+
20+export interface PendingL1 {
21+ [key: number]: PendingL1Txn[];
22+}
src/lib/types/Point.ts+25
@@ -9,6 +9,17 @@ export interface Points {
9 [key: number]: Point;
9 [key: number]: Point;
10}
10}
11
11
12+export type PermissionLevel =
13+ | 'own'
14+ | 'manage'
15+ | 'spawn'
16+ | 'vote'
17+ | 'transfer'
18+ | null;
19+
20+export const shouldDisplayPermissionLevel = (level: PermissionLevel) =>
21+ level === 'manage' || level === 'spawn' || level === 'vote';
22+
12export enum PointField {
23export enum PointField {
13 value = 'value',
24 value = 'value',
14 layer = 'layer',
25 layer = 'layer',
@@ -113,6 +124,8 @@ export default class Point {
113 ownManageSpawn: boolean;
124 ownManageSpawn: boolean;
114 shouldDisplay: boolean;
125 shouldDisplay: boolean;
115 isOutgoing: boolean;
126 isOutgoing: boolean;
127+ permissionLevel: PermissionLevel;
128+ displayPermission: boolean;
116
129
117 constructor({
130 constructor({
118 value,
131 value,
@@ -157,6 +170,18 @@ export default class Point {
157 this.isSpawnProxy = eqAddr(address, this.spawnProxy);
170 this.isSpawnProxy = eqAddr(address, this.spawnProxy);
158 this.isVotingProxy = eqAddr(address, this.votingProxy);
171 this.isVotingProxy = eqAddr(address, this.votingProxy);
159 this.isTransferProxy = eqAddr(address, this.transferProxy);
172 this.isTransferProxy = eqAddr(address, this.transferProxy);
173+ this.permissionLevel = this.isOwner
174+ ? 'own'
175+ : this.isManagementProxy
176+ ? 'manage'
177+ : this.isSpawnProxy
178+ ? 'spawn'
179+ : this.isVotingProxy
180+ ? 'vote'
181+ : this.isTransferProxy
182+ ? 'transfer'
183+ : null;
184+ this.displayPermission = shouldDisplayPermissionLevel(this.permissionLevel);
160 this.isManagementProxySet = !isZeroAddress(this.managementProxy);
185 this.isManagementProxySet = !isZeroAddress(this.managementProxy);
161 this.isSpawnProxySet = !isZeroAddress(this.spawnProxy);
186 this.isSpawnProxySet = !isZeroAddress(this.spawnProxy);
162 this.isVotingProxySet = !isZeroAddress(this.votingProxy);
187 this.isVotingProxySet = !isZeroAddress(this.votingProxy);
src/lib/useRoller.ts+16−7
@@ -50,9 +50,18 @@ import { L1Point } from './types/L1Point';
50import { ddmmmYYYY } from './utils/date';
50import { ddmmmYYYY } from './utils/date';
51import { showNotification } from './utils/notifications';
51import { showNotification } from './utils/notifications';
52import { useWalletConnect } from './useWalletConnect';
52import { useWalletConnect } from './useWalletConnect';
53+import { PendingL1Txn } from './types/PendingL1Transaction';
53
54
54const ONE_SECOND = 1000;
55const ONE_SECOND = 1000;
55
56
57+interface UpdateParams {
58+ point: number;
59+ message?: string;
60+ notify?: boolean;
61+ field?: PointField;
62+ l1Txn?: PendingL1Txn;
63+}
64+
56const inviteTemplate = (
65const inviteTemplate = (
57 planet: number,
66 planet: number,
58 ticket = '',
67 ticket = '',
@@ -98,6 +107,8 @@ export default function useRoller() {
98 setPoints,
107 setPoints,
99 updateInvite,
108 updateInvite,
100 updatePoint,
109 updatePoint,
110+ storePendingL1Txn,
111+ deletePendingL1Txn,
101 } = useRollerStore();
112 } = useRollerStore();
102 const [config, setConfig] = useState<Config | null>(null);
113 const [config, setConfig] = useState<Config | null>(null);
103
114
@@ -228,12 +239,9 @@ export default function useRoller() {
228 );
239 );
229
240
230 const checkForUpdates = useCallback(
241 const checkForUpdates = useCallback(
231− async (
242+ async ({ point, message, notify = true, field, l1Txn }: UpdateParams) => {
232− point: number,
243+ if (l1Txn) storePendingL1Txn(l1Txn);
233− message?: string,
244+
234− notify = true,
235− field?: PointField
236− ) => {
237 const interval = setInterval(async () => {
245 const interval = setInterval(async () => {
238 const updatedPoint = await initPoint(point);
246 const updatedPoint = await initPoint(point);
239 const changedField = !points[point]
247 const changedField = !points[point]
@@ -247,6 +255,7 @@ export default function useRoller() {
247 if (!updatedPoint.isPlaceholder && changedField) {
255 if (!updatedPoint.isPlaceholder && changedField) {
248 updatePoint(updatedPoint);
256 updatePoint(updatedPoint);
249 clearInterval(interval);
257 clearInterval(interval);
258+ if (l1Txn) deletePendingL1Txn(l1Txn);
250 if (notify) {
259 if (notify) {
251 showNotification(
260 showNotification(
252 `${message || getUpdatedPointMessage(updatedPoint, changedField)}`
261 `${message || getUpdatedPointMessage(updatedPoint, changedField)}`
@@ -255,7 +264,7 @@ export default function useRoller() {
255 }
264 }
256 }, TEN_SECONDS);
265 }, TEN_SECONDS);
257 },
266 },
258− [points, initPoint, updatePoint]
267+ [points, initPoint, updatePoint, storePendingL1Txn, deletePendingL1Txn]
259 );
268 );
260
269
261 const spawnPoint = useCallback(
270 const spawnPoint = useCallback(
src/store/rollerStore.ts+18
@@ -5,6 +5,7 @@ import { HOUR } from 'lib/utils/roller';
5import { Invite, Invites } from 'lib/types/Invite';
5import { Invite, Invites } from 'lib/types/Invite';
6import Point, { Points } from 'lib/types/Point';
6import Point, { Points } from 'lib/types/Point';
7import { toL1Details } from 'lib/utils/point';
7import { toL1Details } from 'lib/utils/point';
8+import { PendingL1, PendingL1Txn } from 'lib/types/PendingL1Transaction';
8
9
9const getPointsAndList = (points: Points, point: Point) => ({
10const getPointsAndList = (points: Points, point: Point) => ({
10 points,
11 points,
@@ -26,6 +27,7 @@ export interface RollerStore {
26 point: Point;
27 point: Point;
27 points: Points;
28 points: Points;
28 pointList: Point[];
29 pointList: Point[];
30+ pendingL1ByPoint: PendingL1;
29 invites: Invites;
31 invites: Invites;
30 modalText?: string;
32 modalText?: string;
31 recentlyCompleted: number;
33 recentlyCompleted: number;
@@ -44,6 +46,8 @@ export interface RollerStore {
44 setPoints: (points: Points) => void;
46 setPoints: (points: Points) => void;
45 updateInvite: (point: number, invite: Invite) => void;
47 updateInvite: (point: number, invite: Invite) => void;
46 updatePoint: (point: Point) => void;
48 updatePoint: (point: Point) => void;
49+ storePendingL1Txn: (txn: PendingL1Txn) => void;
50+ deletePendingL1Txn: (txn: PendingL1Txn) => void;
47}
51}
48
52
49export const useRollerStore = create<RollerStore>(set => ({
53export const useRollerStore = create<RollerStore>(set => ({
@@ -54,6 +58,7 @@ export const useRollerStore = create<RollerStore>(set => ({
54 point: EMPTY_POINT,
58 point: EMPTY_POINT,
55 pointList: [],
59 pointList: [],
56 points: {},
60 points: {},
61+ pendingL1ByPoint: {},
57 invites: {},
62 invites: {},
58 recentlyCompleted: 0,
63 recentlyCompleted: 0,
59 inviteGeneratingNum: 0,
64 inviteGeneratingNum: 0,
@@ -110,4 +115,17 @@ export const useRollerStore = create<RollerStore>(set => ({
110 return getPointsAndList(newPoints, point);
115 return getPointsAndList(newPoints, point);
111 }),
116 }),
112 setModalText: (modalText?: string) => set(() => ({ modalText })),
117 setModalText: (modalText?: string) => set(() => ({ modalText })),
118+ storePendingL1Txn: (txn: PendingL1Txn) =>
119+ set(({ pendingL1ByPoint }) => {
120+ const newPending = Object.assign({}, pendingL1ByPoint);
121+ newPending[txn.point] = [...(pendingL1ByPoint[txn.point] || []), txn];
122+ return { pendingL1ByPoint: newPending };
123+ }),
124+ deletePendingL1Txn: (txn: PendingL1Txn) =>
125+ set(({ pendingL1ByPoint }) => {
126+ const newPending = Object.assign({}, pendingL1ByPoint);
127+ newPending[txn.point] =
128+ pendingL1ByPoint[txn.point]?.filter(({ id }) => id !== txn.id) || [];
129+ return { pendingL1ByPoint: newPending };
130+ }),
113}));
131}));
src/views/AcceptTransfer.js → src/views/AcceptTransfer.tsxrenamed+16−15
@@ -29,10 +29,10 @@ import { useRollerStore } from 'store/rollerStore';
29import useRoller from 'lib/useRoller';
29import useRoller from 'lib/useRoller';
30
30
31function useAcceptTransfer() {
31function useAcceptTransfer() {
32− const { contracts } = useNetwork();
32+ const { contracts }: any = useNetwork();
33− const { pointCursor } = usePointCursor();
33+ const { pointCursor }: any = usePointCursor();
34− const { syncExtras, syncControlledPoints } = usePointCache();
34+ const { syncExtras, syncControlledPoints }: any = usePointCache();
35− const { wallet } = useWallet();
35+ const { wallet }: any = useWallet();
36
36
37 const _contracts = need.contracts(contracts);
37 const _contracts = need.contracts(contracts);
38 const _point = need.point(pointCursor);
38 const _point = need.point(pointCursor);
@@ -57,12 +57,12 @@ function useAcceptTransfer() {
57}
57}
58
58
59export default function AcceptTransfer() {
59export default function AcceptTransfer() {
60− const { pop } = useLocalRouter();
60+ const { pop }: any = useLocalRouter();
61− const { setPointCursor } = usePointCursor();
61+ const { setPointCursor }: any = usePointCursor();
62 const { point } = useRollerStore();
62 const { point } = useRollerStore();
63 const { transferPoint, checkForUpdates } = useRoller();
63 const { transferPoint, checkForUpdates } = useRoller();
64
64
65− const { wallet } = useWallet();
65+ const { wallet }: any = useWallet();
66 const _address = need.addressFromWallet(wallet);
66 const _address = need.addressFromWallet(wallet);
67
67
68 const name = useCurrentPointName();
68 const name = useCurrentPointName();
@@ -73,10 +73,10 @@ export default function AcceptTransfer() {
73
73
74 useEffect(() => {
74 useEffect(() => {
75 if (completed) {
75 if (completed) {
76− checkForUpdates(
76+ checkForUpdates({
77− point.value,
77+ point: point.value,
78− `${point.patp} has been transferred to you!`
78+ message: `${point.patp} has been transferred to you!`,
79− );
79+ });
80 }
80 }
81 }, [completed]); // eslint-disable-line react-hooks/exhaustive-deps
81 }, [completed]); // eslint-disable-line react-hooks/exhaustive-deps
82
82
@@ -101,10 +101,11 @@ export default function AcceptTransfer() {
101
101
102 const acceptTransfer = useCallback(async () => {
102 const acceptTransfer = useCallback(async () => {
103 await transferPoint(_address, reset);
103 await transferPoint(_address, reset);
104− await checkForUpdates(
104+ await checkForUpdates({
105− point.value,
105+ point: point.value,
106− `${point.patp} has been transferred to you!`
106+ message: `${point.patp} has been transferred to you!`,
107− );
107+ });
108+
108 goBack();
109 goBack();
109 }, [goBack, transferPoint, checkForUpdates, point, _address, reset]);
110 }, [goBack, transferPoint, checkForUpdates, point, _address, reset]);
110
111
src/views/CancelTransfer.js+8−2
@@ -67,7 +67,10 @@ function AdminCancelTransfer() {
67
67
68 useEffect(() => {
68 useEffect(() => {
69 if (completed) {
69 if (completed) {
70+ checkForUpdates({
71+ point: point.value,
70− checkForUpdates(point.value, `${point.patp} transfer cancelled`);
72+ message: `${point.patp} transfer cancelled`,
73+ });
71 }
74 }
72 }, [completed]); // eslint-disable-line react-hooks/exhaustive-deps
75 }, [completed]); // eslint-disable-line react-hooks/exhaustive-deps
73
76
@@ -78,7 +81,10 @@ function AdminCancelTransfer() {
78
81
79 const cancelTransfer = useCallback(async () => {
82 const cancelTransfer = useCallback(async () => {
80 await setProxyAddress('transfer', ETH_ZERO_ADDR);
83 await setProxyAddress('transfer', ETH_ZERO_ADDR);
84+ await checkForUpdates({
85+ point: point.value,
81− await checkForUpdates(point.value, `${point.patp} transfer cancelled`);
86+ message: `${point.patp} transfer cancelled`,
87+ });
82 goBack();
88 goBack();
83 }, [setProxyAddress, goBack, checkForUpdates, point]);
89 }, [setProxyAddress, goBack, checkForUpdates, point]);
84
90
src/views/Point/IssueChild.tsx+12−2
@@ -24,6 +24,7 @@ import { validateChild } from 'lib/validators';
24import { convertToInt } from 'lib/convertToInt';
24import { convertToInt } from 'lib/convertToInt';
25import { isGalaxy } from 'lib/utils/point';
25import { isGalaxy } from 'lib/utils/point';
26import useRoller from 'lib/useRoller';
26import useRoller from 'lib/useRoller';
27+import { L1TxnType } from 'lib/types/PendingL1Transaction';
27
28
28import InlineEthereumTransaction from 'components/InlineEthereumTransaction';
29import InlineEthereumTransaction from 'components/InlineEthereumTransaction';
29import View from 'components/View';
30import View from 'components/View';
@@ -118,7 +119,7 @@ export default function IssueChild() {
118 if (pointToSpawn && destinationAddress) {
119 if (pointToSpawn && destinationAddress) {
119 setLoading(true);
120 setLoading(true);
120 await spawnPoint(pointToSpawn, destinationAddress);
121 await spawnPoint(pointToSpawn, destinationAddress);
121− checkForUpdates(pointToSpawn);
122+ checkForUpdates({ point: pointToSpawn });
122 setPointToSpawn(null);
123 setPointToSpawn(null);
123 setDestinationAddress(null);
124 setDestinationAddress(null);
124 setL2SpawnSent(true);
125 setL2SpawnSent(true);
@@ -133,11 +134,20 @@ export default function IssueChild() {
133 completed,
134 completed,
134 inputsLocked,
135 inputsLocked,
135 bind,
136 bind,
137+ txHashes,
136 } = useIssueChild();
138 } = useIssueChild();
137
139
138 useEffect(() => {
140 useEffect(() => {
139 if (completed && pointToSpawn) {
141 if (completed && pointToSpawn) {
140− checkForUpdates(pointToSpawn);
142+ checkForUpdates({
143+ point: pointToSpawn,
144+ l1Txn: {
145+ id: `${pointToSpawn}`,
146+ point: point.value,
147+ type: L1TxnType.spawnPoint,
148+ hash: txHashes[0],
149+ },
150+ });
141 }
151 }
142 }, [completed]); // eslint-disable-line react-hooks/exhaustive-deps
152 }, [completed]); // eslint-disable-line react-hooks/exhaustive-deps
143
153
src/views/Point/MigrateL2.tsx+32−17
@@ -3,14 +3,31 @@ import { Grid } from 'indigo-react';
3import { ecliptic } from 'azimuth-js';
3import { ecliptic } from 'azimuth-js';
4import * as ob from 'urbit-ob';
4import * as ob from 'urbit-ob';
5
5
6+import {
7+ getHideMigrationMessage,
8+ storeHideMigrationMessage,
9+} from 'store/storage/roller';
10+import { useNetwork } from 'store/network';
11+import { usePointCache } from 'store/pointCache';
12+import { useRollerStore } from 'store/rollerStore';
13+
6import { useLocalRouter } from 'lib/LocalRouter';
14import { useLocalRouter } from 'lib/LocalRouter';
7import * as need from 'lib/need';
15import * as need from 'lib/need';
16+import Point, { PointField } from 'lib/types/Point';
17+import useRoller from 'lib/useRoller';
18+import { L1TxnType } from 'lib/types/PendingL1Transaction';
19+import useEthereumTransaction from 'lib/useEthereumTransaction';
20+import { DUMMY_L2_ADDRESS, GAS_LIMITS } from 'lib/constants';
21+import { isPlanet } from 'lib/utils/point';
8
22
9import View from 'components/View';
23import View from 'components/View';
10import L2BackHeader from 'components/L2/Headers/L2BackHeader';
24import L2BackHeader from 'components/L2/Headers/L2BackHeader';
11import BodyPane from 'components/L2/Window/BodyPane';
25import BodyPane from 'components/L2/Window/BodyPane';
12import HeaderPane from 'components/L2/Window/HeaderPane';
26import HeaderPane from 'components/L2/Window/HeaderPane';
13import Window from 'components/L2/Window/Window';
27import Window from 'components/L2/Window/Window';
28+import InlineEthereumTransaction from 'components/InlineEthereumTransaction';
29+import Dropdown from 'components/L2/Dropdowns/Dropdown';
30+import Sigil from 'components/Sigil';
14import { ReactComponent as StarIcon } from 'assets/star.svg';
31import { ReactComponent as StarIcon } from 'assets/star.svg';
15
32
16import {
33import {
@@ -21,23 +38,8 @@ import {
21 RadioButton,
38 RadioButton,
22 Row,
39 Row,
23} from '@tlon/indigo-react';
40} from '@tlon/indigo-react';
24−import {
25− getHideMigrationMessage,
26− storeHideMigrationMessage,
27−} from 'store/storage/roller';
28−import InlineEthereumTransaction from 'components/InlineEthereumTransaction';
29−import { useNetwork } from 'store/network';
30−import { usePointCache } from 'store/pointCache';
31−import useEthereumTransaction from 'lib/useEthereumTransaction';
32−import { DUMMY_L2_ADDRESS, GAS_LIMITS } from 'lib/constants';
33−import Dropdown from 'components/L2/Dropdowns/Dropdown';
34−import Sigil from 'components/Sigil';
35−import { isPlanet } from 'lib/utils/point';
36
41
37import './MigrateL2.scss';
42import './MigrateL2.scss';
38−import { useRollerStore } from 'store/rollerStore';
39−import Point, { PointField } from 'lib/types/Point';
40−import useRoller from 'lib/useRoller';
41
43
42const PointEntry = ({
44const PointEntry = ({
43 point,
45 point,
@@ -113,7 +115,7 @@ export default function MigrateL2() {
113 );
115 );
114 const hideInfo = getHideMigrationMessage();
116 const hideInfo = getHideMigrationMessage();
115
117
116− const { construct, unconstruct, bind, completed } = useMigrate();
118+ const { construct, unconstruct, bind, completed, txHashes } = useMigrate();
117
119
118 useEffect(() => {
120 useEffect(() => {
119 if (point.isGalaxy && point.isL1) {
121 if (point.isGalaxy && point.isL1) {
@@ -131,7 +133,20 @@ export default function MigrateL2() {
131 const message = transfer
133 const message = transfer
132 ? `${selectedPoint.patp} has been migrated to Layer 2!`
134 ? `${selectedPoint.patp} has been migrated to Layer 2!`
133 : `${selectedPoint.patp}'s spawn proxy has been set to Layer 2!`;
135 : `${selectedPoint.patp}'s spawn proxy has been set to Layer 2!`;
136+
137+ checkForUpdates({
134− checkForUpdates(selectedPoint.value, message, true, PointField.layer);
138+ point: selectedPoint.value,
139+ message,
140+ notify: true,
141+ field: PointField.layer,
142+ l1Txn: {
143+ id: `${DUMMY_L2_ADDRESS}-${selectedPoint.value}`,
144+ point: selectedPoint.value,
145+ type: transfer ? L1TxnType.migrate : L1TxnType.migrateSpawn,
146+ hash: txHashes[0],
147+ },
148+ });
149+
135 pop();
150 pop();
136 }
151 }
137 }, [completed, pop]); // eslint-disable-line react-hooks/exhaustive-deps
152 }, [completed, pop]); // eslint-disable-line react-hooks/exhaustive-deps
src/views/Point/Point.scss−47
@@ -3,53 +3,6 @@
3.point {
3.point {
4}
4}
5
5
6−.transaction {
7− font-size: 14px;
8− padding: 8px;
9− border: 1px solid $light-gray;
10− border-radius: $large-border-radius;
11− margin-bottom: 16px;
12−
13− .title-row {
14− display: flex;
15− flex-direction: row;
16− justify-content: space-between;
17− align-items: center;
18−
19− .title {
20− font-weight: 600;
21− }
22−
23− .rollup-timer {
24− background-color: $rollup-yellow;
25− padding: 4px 8px;
26− width: 112px;
27− border-radius: $medium-border-radius;
28− display: flex;
29− flex-direction: row;
30− justify-content: center;
31− align-items: center;
32−
33− svg {
34− height: 14px;
35− width: 14px;
36− margin-right: 4px;
37− }
38− }
39− }
40−
41− .info-row {
42− display: flex;
43− flex-direction: row;
44− justify-content: space-between;
45− align-items: center;
46−
47− .date {
48−
49− }
50− }
51−}
52−
53.network-keys-modal {
6.network-keys-modal {
54 background-color: white;
7 background-color: white;
55 border-radius: $medium-border-radius;
8 border-radius: $medium-border-radius;
src/views/Point/Point.tsx+26−38
@@ -23,17 +23,23 @@ import useRoller from 'lib/useRoller';
23import useSeenMissingKeys from 'lib/useSeenMissingKeys';
23import useSeenMissingKeys from 'lib/useSeenMissingKeys';
24import { useHasNetworkKeysSet } from 'lib/useHasNetworkKeysSet';
24import { useHasNetworkKeysSet } from 'lib/useHasNetworkKeysSet';
25
25
26−import { InviteForm } from './InviteForm';
26+import LoadingOverlay from 'components/L2/LoadingOverlay';
27+import PendingTransaction, { getPendingL1Title, getPendingTitle } from 'components/L2/PendingTransaction';
27import Modal from 'components/L2/Modal';
28import Modal from 'components/L2/Modal';
29+import { InviteForm } from './InviteForm';
28import './Point.scss';
30import './Point.scss';
29−import LoadingOverlay from 'components/L2/LoadingOverlay';
30
31
31export default function Point() {
32export default function Point() {
32 const { pop, push, names }: any = useLocalRouter();
33 const { pop, push, names }: any = useLocalRouter();
33 const { wallet }: any = useWallet();
34 const { wallet }: any = useWallet();
34 const { syncExtras }: any = usePointCache();
35 const { syncExtras }: any = usePointCache();
35 const { getInvites, getPendingTransactions } = useRoller();
36 const { getInvites, getPendingTransactions } = useRoller();
37+ const {
36− const { pendingTransactions, point, invites } = useRollerStore();
38+ pendingTransactions,
39+ point,
40+ invites,
41+ pendingL1ByPoint,
42+ } = useRollerStore();
37 const { nextRoll } = useTimerStore();
43 const { nextRoll } = useTimerStore();
38 const networkKeysSet = useHasNetworkKeysSet();
44 const networkKeysSet = useHasNetworkKeysSet();
39 const [seenMissingKeys, setSeenMissingKeys] = useSeenMissingKeys();
45 const [seenMissingKeys, setSeenMissingKeys] = useSeenMissingKeys();
@@ -43,6 +49,8 @@ export default function Point() {
43
49
44 const pointRef = useRef<number | null>(null);
50 const pointRef = useRef<number | null>(null);
45
51
52+ const pendingL1Transactions = pendingL1ByPoint[point.value] || [];
53+
46 const hideModal = useCallback(() => {
54 const hideModal = useCallback(() => {
47 if (hideMessage) {
55 if (hideMessage) {
48 setSeenMissingKeys(true);
56 setSeenMissingKeys(true);
@@ -155,41 +163,21 @@ export default function Point() {
155 )}
163 )}
156 {!!otherPending.length &&
164 {!!otherPending.length &&
157 otherPending.map((pendingTx, ind) => (
165 otherPending.map((pendingTx, ind) => (
166+ <PendingTransaction
158− <div className="transaction" key={`pending-${ind}`}>
167+ key={`pending-tx-${ind}`}
159− <Row className="title-row">
168+ layer={2}
160− <div className="title">
169+ nextRoll={nextRoll}
161− {pendingTx.rawTx?.tx?.type === 'set-management-proxy'
170+ title={getPendingTitle(pendingTx.rawTx?.tx?.type)}
162− ? 'Management Address Changed'
171+ />
163− : pendingTx.rawTx?.tx?.type === 'configure-keys'
172+ ))}
164− ? 'Network Keys Configured'
173+ {!!pendingL1Transactions.length &&
165− : pendingTx.rawTx?.tx?.type === 'transfer-point'
174+ pendingL1Transactions.map((pendingTx, ind) => (
166− ? 'Point Transfered'
175+ <PendingTransaction
167− : pendingTx.rawTx?.tx?.type === 'set-transfer-proxy'
176+ key={`pending-tx-${ind}`}
168− ? 'Transfer Proxy Changed'
177+ layer={1}
169− : pendingTx.rawTx?.tx?.type === 'set-spawn-proxy'
178+ hash={pendingTx.hash}
170− ? 'Spawn Proxy Changed'
179+ title={getPendingL1Title(pendingTx.type)}
171− : pendingTx.rawTx?.tx?.type === 'escape'
180+ />
172− ? 'Change Sponsor'
173− : pendingTx.rawTx?.tx?.type === 'cancel-escape'
174− ? 'Cancel Escape'
175− : pendingTx.rawTx?.tx?.type === 'adopt'
176− ? 'Accept Sponsorship'
177− : pendingTx.rawTx?.tx?.type === 'reject'
178− ? 'Reject Sponsorship'
179− : pendingTx.rawTx?.tx?.type === 'detach'
180− ? 'Detach Sponsee'
181− : ''}
182− </div>
183− <div className="rollup-timer">
184− <Icon icon="Clock" />
185− {nextRoll}
186− </div>
187− </Row>
188− <Row className="info-row">
189− <LayerIndicator layer={2} size="sm" />
190− <div className="date"></div>
191− </Row>
192− </div>
193 ))}
181 ))}
194 <Passport
182 <Passport
195 point={Just(point.value)}
183 point={Just(point.value)}
src/views/Points.tsx+25−62
@@ -12,15 +12,15 @@ import { useNetwork } from 'store/network';
12import { useRollerStore } from 'store/rollerStore';
12import { useRollerStore } from 'store/rollerStore';
13
13
14import * as need from 'lib/need';
14import * as need from 'lib/need';
15−import { isZeroAddress, abbreviateAddress } from 'lib/utils/address';
15+import { abbreviateAddress } from 'lib/utils/address';
16import useIsEclipticOwner from 'lib/useIsEclipticOwner';
16import useIsEclipticOwner from 'lib/useIsEclipticOwner';
17import { useSyncDetails } from 'lib/useSyncPoints';
17import { useSyncDetails } from 'lib/useSyncPoints';
18import useRejectedIncomingPointTransfers from 'lib/useRejectedIncomingPointTransfers';
18import useRejectedIncomingPointTransfers from 'lib/useRejectedIncomingPointTransfers';
19import { pluralize } from 'lib/pluralize';
19import { pluralize } from 'lib/pluralize';
20+import Point from 'lib/types/Point';
20import newGithubIssueUrl from 'new-github-issue-url';
21import newGithubIssueUrl from 'new-github-issue-url';
21
22
22import View from 'components/View';
23import View from 'components/View';
23−import Passport from 'components/Passport';
24import Footer from 'components/Footer';
24import Footer from 'components/Footer';
25import { ForwardButton } from 'components/Buttons';
25import { ForwardButton } from 'components/Buttons';
26import CopiableAddress from 'components/copiable/CopiableAddress';
26import CopiableAddress from 'components/copiable/CopiableAddress';
@@ -28,6 +28,7 @@ import NavHeader from 'components/NavHeader';
28import L2PointHeader from 'components/L2/Headers/L2PointHeader';
28import L2PointHeader from 'components/L2/Headers/L2PointHeader';
29import IncomingPoint from 'components/L2/Points/IncomingPoint';
29import IncomingPoint from 'components/L2/Points/IncomingPoint';
30import LoadingOverlay from 'components/L2/LoadingOverlay';
30import LoadingOverlay from 'components/L2/LoadingOverlay';
31+import PointList from 'components/L2/PointList';
31import { Box, Text } from '@tlon/indigo-react';
32import { Box, Text } from '@tlon/indigo-react';
32
33
33import './Points.scss';
34import './Points.scss';
@@ -42,56 +43,18 @@ export const maybeGetResult = (obj, key, defaultValue) =>
42 }),
43 }),
43 });
44 });
44
45
45−export const hasTransferProxy = details =>
46− !isZeroAddress(details.transferProxy);
47−
48−export const isLocked = (details, contracts) =>
46+export const isLocked = (details: any, contracts: any) =>
49 details.owner === contracts.linearSR ||
47 details.owner === contracts.linearSR ||
50 details.owner === contracts.conditionalSR;
48 details.owner === contracts.conditionalSR;
51
49
52−const PointList = function({
50+interface ActionButtonProps {
53− points,
54− className,
55− actions,
51+ actions?: {
56− locked = false,
52+ text?: string;
57− processing = false,
58− ...rest
59−}) {
60− const { setPointCursor } = usePointCursor();
61− const { push, names } = useHistory();
62−
63− return (
64− <Grid gap={4} className={className}>
65− {points.map((point, i) => (
66− <Grid.Item
67− key={point}
68− className={`full fourth-${(i % 4) + 1}-md fourth-${(i % 4) + 1}-lg`}>
69− <Flex col>
70− <Passport.Mini
71− locked={locked}
72− processing={processing}
73− point={point}
74− onClick={
53+ onClick?: () => void;
75− locked || processing
54+ }[];
76− ? undefined
77− : () => {
78− setPointCursor(Just(point));
79− push(names.POINT);
80− }
81− }
82− {...rest}
83− />
84− {actions && (
85− <Flex.Item className="mt2">{actions(point, i)}</Flex.Item>
86− )}
87− </Flex>
88− </Grid.Item>
89− ))}
90− </Grid>
91− );
92−};
55+}
93
56
94−function ActionButtons({ actions = [] }) {
57+function ActionButtons({ actions = [] }: ActionButtonProps) {
95 return (
58 return (
96 <Flex row>
59 <Flex row>
97 {actions.map(action => (
60 {actions.map(action => (
@@ -164,9 +127,7 @@ export default function Points() {
164 [getDetails, controlledPoints, _contracts]
127 [getDetails, controlledPoints, _contracts]
165 );
128 );
166
129
167− const allPoints = pointList
168− .filter(({ shouldDisplay }) => shouldDisplay)
130+ const allPoints = pointList.filter(({ shouldDisplay }) => shouldDisplay);
169− .map(({ value }) => value);
170
131
171 // if we can only interact with a single point, jump to the point page.
132 // if we can only interact with a single point, jump to the point page.
172 // if there are any pending transfers, incoming or outgoing, stay on this
133 // if there are any pending transfers, incoming or outgoing, stay on this
@@ -182,7 +143,7 @@ export default function Points() {
182 (starReleaseDetails.value === null ||
143 (starReleaseDetails.value === null ||
183 starReleaseDetails.value.total === 0)
144 starReleaseDetails.value.total === 0)
184 ) {
145 ) {
185− setPointCursor(Just(allPoints[0]));
146+ setPointCursor(Just(allPoints[0].value));
186 push(names.POINT);
147 push(names.POINT);
187 }
148 }
188 }, [
149 }, [
@@ -201,11 +162,13 @@ export default function Points() {
201 const loading = Nothing.hasInstance(controlledPoints);
162 const loading = Nothing.hasInstance(controlledPoints);
202
163
203 const ownedPoints = maybeGetResult(controlledPoints, 'ownedPoints', []);
164 const ownedPoints = maybeGetResult(controlledPoints, 'ownedPoints', []);
204− const lockedPoints = maybeLockedPoints.getOrElse([]);
165+ const lockedPoints = maybeLockedPoints
166+ .getOrElse([])
167+ .map((value: number) => ({ value }));
205
168
206− const processingPoints = pointList
169+ const processingPoints = pointList.filter(
207− .filter(({ shouldDisplay }) => !shouldDisplay)
170+ ({ shouldDisplay }) => !shouldDisplay
208− .map(({ value }) => value);
171+ );
209
172
210 const displayEmptyState =
173 const displayEmptyState =
211 !loading && incomingPoints.length === 0 && allPoints.length === 0;
174 !loading && incomingPoints.length === 0 && allPoints.length === 0;
@@ -331,14 +294,14 @@ export default function Points() {
331 <Grid.Item
294 <Grid.Item
332 full
295 full
333 as={PointList}
296 as={PointList}
334− points={outgoingPoints.map(({ value }) => value)}
297+ points={outgoingPoints}
335− actions={(point, i) => (
298+ actions={(point: Point, i: number) => (
336 <ActionButtons
299 <ActionButtons
337 actions={[
300 actions={[
338 {
301 {
339 text: 'Cancel',
302 text: 'Cancel',
340 onClick: () => {
303 onClick: () => {
341− setPointCursor(Just(point));
304+ setPointCursor(Just(point.value));
342 // TODO: deep linking to fix this duplicate route
305 // TODO: deep linking to fix this duplicate route
343 push(names.CANCEL_TRANSFER);
306 push(names.CANCEL_TRANSFER);
344 },
307 },
@@ -358,11 +321,11 @@ export default function Points() {
358
321
359 {lockedPoints.length > 0 && (
322 {lockedPoints.length > 0 && (
360 <Grid.Item full as={Grid} gap={1}>
323 <Grid.Item full as={Grid} gap={1}>
361− <Grid.Item full as={PointList} locked points={allPoints} />
324+ <Grid.Item full as={PointList} locked points={lockedPoints} />
362 </Grid.Item>
325 </Grid.Item>
363 )}
326 )}
364
327
365− {processingPoints.length > 0 && (
328+ {/* {processingPoints.length > 0 && (
366 <Grid.Item full as={Grid} gap={1} className="mv6">
329 <Grid.Item full as={Grid} gap={1} className="mv6">
367 <Grid.Item full as={H5}>
330 <Grid.Item full as={H5}>
368 Awaiting L2 Rollup
331 Awaiting L2 Rollup
@@ -374,7 +337,7 @@ export default function Points() {
374 processing
337 processing
375 />
338 />
376 </Grid.Item>
339 </Grid.Item>
377− )}
340+ )} */}
378
341
379 <Footer>
342 <Footer>
380 <Grid>
343 <Grid>
src/views/UrbitID/SetProxy.js+20−4
@@ -14,6 +14,7 @@ import {
14 PROXY_TYPE,
14 PROXY_TYPE,
15 proxyTypeToHuman,
15 proxyTypeToHuman,
16 proxyTypeToHumanDescription,
16 proxyTypeToHumanDescription,
17+ proxyTypeToL1TxnType,
17} from 'lib/proxy';
18} from 'lib/proxy';
18import * as need from 'lib/need';
19import * as need from 'lib/need';
19import { useLocalRouter } from 'lib/LocalRouter';
20import { useLocalRouter } from 'lib/LocalRouter';
@@ -152,6 +153,7 @@ export default function SetProxy() {
152 inputsLocked,
153 inputsLocked,
153 completed,
154 completed,
154 bind,
155 bind,
156+ txHashes,
155 } = useSetProxy(data.proxyType);
157 } = useSetProxy(data.proxyType);
156
158
157 const setProxy = useCallback(async () => {
159 const setProxy = useCallback(async () => {
@@ -159,6 +161,12 @@ export default function SetProxy() {
159 if (newAddress === '') return;
161 if (newAddress === '') return;
160 try {
162 try {
161 await setProxyAddress(getL2ProxyName(data.proxyType), newAddress);
163 await setProxyAddress(getL2ProxyName(data.proxyType), newAddress);
164+
165+ checkForUpdates({
166+ point: point.value,
167+ message: `${point.patp}'s ${humanProxyType} proxy has been set!`,
168+ });
169+
162 getPendingTransactions(point.value);
170 getPendingTransactions(point.value);
163 pop();
171 pop();
164 } catch (error) {
172 } catch (error) {
@@ -174,14 +182,22 @@ export default function SetProxy() {
174 data.proxyType,
182 data.proxyType,
175 setProxyAddress,
183 setProxyAddress,
176 setLoading,
184 setLoading,
185+ checkForUpdates,
186+ humanProxyType,
177 ]);
187 ]);
178
188
179 useEffect(() => {
189 useEffect(() => {
180 if (completed) {
190 if (completed) {
181− checkForUpdates(
191+ checkForUpdates({
182− point.value,
192+ point: point.value,
183− `${point.patp}'s ${humanProxyType} proxy has been set!`
193+ message: `${point.patp}'s ${humanProxyType} proxy has been set!`,
194+ l1Txn: {
195+ id: `${newAddress}-${point.value}`,
196+ point: point.value,
197+ type: proxyTypeToL1TxnType(data.proxyType),
198+ hash: txHashes[0],
199+ },
184− );
200+ });
185 }
201 }
186 }, [completed]); // eslint-disable-line react-hooks/exhaustive-deps
202 }, [completed]); // eslint-disable-line react-hooks/exhaustive-deps
187
203
src/views/UrbitOS/ChangeSponsor.js+6−4
@@ -62,10 +62,12 @@ function ChangeSponsor({ onDone }) {
62 if (newSponsor !== undefined) {
62 if (newSponsor !== undefined) {
63 setLoading(true);
63 setLoading(true);
64 await changeSponsor(newSponsor);
64 await changeSponsor(newSponsor);
65− checkForUpdates(
65+ checkForUpdates({
66− point.value,
66+ point: point.value,
67− `${point.patp} has requested ${ob.patp(newSponsor)} as a sponsor`
67+ message: `${point.patp} has requested ${ob.patp(
68+ newSponsor
69+ )} as a sponsor`,
68− );
70+ });
69 setLoading(false);
71 setLoading(false);
70 pop();
72 pop();
71 }
73 }
src/views/UrbitOS/NetworkKeys.tsx+16−8
@@ -49,6 +49,7 @@ import HeaderPane from 'components/L2/Window/HeaderPane';
49import BodyPane from 'components/L2/Window/BodyPane';
49import BodyPane from 'components/L2/Window/BodyPane';
50
50
51import './NetworkKeys.scss';
51import './NetworkKeys.scss';
52+import { L1TxnType } from 'lib/types/PendingL1Transaction';
52
53
53function useSetKeys(
54function useSetKeys(
54 manualNetworkSeed: string,
55 manualNetworkSeed: string,
@@ -175,14 +176,21 @@ export default function UrbitOSNetworkKeys({
175 inputsLocked,
176 inputsLocked,
176 bind,
177 bind,
177 keyfileBind,
178 keyfileBind,
179+ txHashes,
178 } = useSetKeys(manualNetworkSeed, setManualNetworkSeed);
180 } = useSetKeys(manualNetworkSeed, setManualNetworkSeed);
179
181
180 useEffect(() => {
182 useEffect(() => {
181 if (completed) {
183 if (completed) {
182− checkForUpdates(
184+ checkForUpdates({
183− point.value,
185+ point: point.value,
184− `${point.patp}'s Network Keys have been set!`
186+ message: `${point.patp}'s Network Keys have been set!`,
187+ l1Txn: {
188+ id: `${point.keyRevisionNumber}-network-keys-${point.value}`,
189+ point: point.value,
190+ type: L1TxnType.setNetworkKeys,
191+ hash: txHashes[0],
192+ },
185− );
193+ });
186 }
194 }
187 }, [completed]); // eslint-disable-line react-hooks/exhaustive-deps
195 }, [completed]); // eslint-disable-line react-hooks/exhaustive-deps
188
196
@@ -247,10 +255,10 @@ export default function UrbitOSNetworkKeys({
247 // set since they are in pending in the Roller...
255 // set since they are in pending in the Roller...
248 // we could inspect if there's a changeKeys in the local list of pending txs,...
256 // we could inspect if there's a changeKeys in the local list of pending txs,...
249 //
257 //
250− checkForUpdates(
258+ checkForUpdates({
251− point.value,
259+ point: point.value,
252− `${point.patp}'s Network Keys have been set!`
260+ message: `${point.patp}'s Network Keys have been set!`,
253− );
261+ });
254 pop();
262 pop();
255 } catch (error) {
263 } catch (error) {
256 // setError(error);
264 // setError(error);