@zerodev/smart-routing-address-react-ui 0.0.4 → 0.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. package/dist/_types/components/FeeBreakdown/index.d.ts +14 -0
  2. package/dist/_types/components/FeeBreakdown/index.d.ts.map +1 -1
  3. package/dist/_types/components/TxnItem/index.d.ts +1 -1
  4. package/dist/_types/components/TxnItem/index.d.ts.map +1 -1
  5. package/dist/_types/constants.d.ts +8 -5
  6. package/dist/_types/constants.d.ts.map +1 -1
  7. package/dist/_types/context/SmartRoutingAddressProvider.d.ts.map +1 -1
  8. package/dist/_types/iconAssets.d.ts +0 -1
  9. package/dist/_types/iconAssets.d.ts.map +1 -1
  10. package/dist/_types/pages/Deposit.d.ts.map +1 -1
  11. package/dist/_types/pages/PastDeposits.d.ts.map +1 -1
  12. package/dist/_types/pages/TransactionDetails.d.ts +4 -3
  13. package/dist/_types/pages/TransactionDetails.d.ts.map +1 -1
  14. package/dist/_types/types.d.ts +4 -7
  15. package/dist/_types/types.d.ts.map +1 -1
  16. package/dist/_types/utils/config.d.ts +11 -9
  17. package/dist/_types/utils/config.d.ts.map +1 -1
  18. package/dist/index.cjs +1 -1
  19. package/dist/index.cjs.map +1 -1
  20. package/dist/index.mjs +1144 -1123
  21. package/dist/index.mjs.map +1 -1
  22. package/dist/styles.css +1 -1
  23. package/package.json +5 -5
  24. package/src/components/FeeBreakdown/index.tsx +47 -2
  25. package/src/components/PendingDeposits/index.tsx +1 -1
  26. package/src/components/TxnItem/index.tsx +1 -9
  27. package/src/constants.ts +14 -25
  28. package/src/context/SmartRoutingAddressProvider.tsx +12 -10
  29. package/src/iconAssets.ts +27 -0
  30. package/src/pages/Deposit.tsx +16 -26
  31. package/src/pages/PastDeposits.tsx +1 -4
  32. package/src/pages/TransactionDetails.tsx +58 -49
  33. package/src/types.ts +4 -7
  34. package/src/utils/config.ts +14 -26
@@ -21,6 +21,7 @@ import { AddressDisplay } from '../components/AddressDisplay'
21
21
  import { ErrorRetryCard } from '../components/ErrorRetryCard'
22
22
  import {
23
23
  FeeBreakdownRows,
24
+ FeeDisclosureButton,
24
25
  FeeSummary,
25
26
  LiveValue,
26
27
  } from '../components/FeeBreakdown'
@@ -36,7 +37,6 @@ import { CHAIN_ICONS, PROVIDER_ICONS, TOKEN_ICONS } from '../iconAssets'
36
37
  import type { SourceToken } from '../types'
37
38
  import {
38
39
  getSourceTokenSymbol,
39
- resolveBaseUrl,
40
40
  resolveDestChain,
41
41
  sourceTokensFromFees,
42
42
  } from '../utils/config'
@@ -82,7 +82,7 @@ export function Deposit({
82
82
  const address = success?.address
83
83
  const estimatedFees = success?.estimatedFees ?? []
84
84
 
85
- // allowPartialRoutes lets the server drop source tokens it can't route, so
85
+ // The server only returns estimates for source tokens it can route, so
86
86
  // the routable set is exactly the tokens the fee estimates came back with.
87
87
  const srcTokens = useMemo(
88
88
  () => sourceTokensFromFees(estimatedFees),
@@ -136,7 +136,7 @@ export function Deposit({
136
136
  refetch: refetchDeposits,
137
137
  } = useDepositStatus({
138
138
  address,
139
- baseUrl: resolveBaseUrl(config),
139
+ baseUrl: config.baseUrl,
140
140
  })
141
141
  const newDeposits = useNewDeposits(deposits, hasLoaded)
142
142
  const pastDepositsCount = deposits.length - newDeposits.length
@@ -417,12 +417,19 @@ export function Deposit({
417
417
  label="Estimated fee"
418
418
  value={
419
419
  breakdown ? (
420
- <LiveValue
421
- loading={providerFees.loading}
422
- flashKey={feeFlashKey}
420
+ // The whole value (summary + chevron) toggles the
421
+ // breakdown, not just the arrow.
422
+ <FeeDisclosureButton
423
+ open={feeOpen}
424
+ onToggle={() => setFeeOpen((prev) => !prev)}
423
425
  >
424
- <FeeSummary breakdown={breakdown} />
425
- </LiveValue>
426
+ <LiveValue
427
+ loading={providerFees.loading}
428
+ flashKey={feeFlashKey}
429
+ >
430
+ <FeeSummary breakdown={breakdown} />
431
+ </LiveValue>
432
+ </FeeDisclosureButton>
426
433
  ) : (
427
434
  // Match Min deposit's skeleton so both loading
428
435
  // affordances share one visual language.
@@ -431,24 +438,6 @@ export function Deposit({
431
438
  }
432
439
  info
433
440
  infoTooltip={FEE_INFO.estimatedFee}
434
- trailing={
435
- breakdown ? (
436
- <button
437
- type="button"
438
- onClick={() => setFeeOpen((prev) => !prev)}
439
- aria-expanded={feeOpen}
440
- aria-label={
441
- feeOpen ? 'Hide fee details' : 'Show fee details'
442
- }
443
- className="zd:inline-flex zd:items-center zd:justify-center zd:cursor-pointer"
444
- >
445
- <Icon
446
- name={feeOpen ? 'chevronUp' : 'chevronDown'}
447
- className="zd:w-3.5 zd:h-3.5 zd:text-greyScale"
448
- />
449
- </button>
450
- ) : null
451
- }
452
441
  />
453
442
  {feeOpen && breakdown && (
454
443
  <FeeBreakdownRows breakdown={breakdown} />
@@ -476,6 +465,7 @@ export function Deposit({
476
465
  label={destChain.name}
477
466
  {...(destChainLogo && { logoUri: destChainLogo })}
478
467
  disabled
468
+ loading={!tokenSymbol}
479
469
  />
480
470
  }
481
471
  />
@@ -9,7 +9,6 @@ import type { DepositStage, DepositWithTimestamp } from '../types'
9
9
  import { getTxUrl } from '../utils/chains'
10
10
  import {
11
11
  getSourceTokenSymbol,
12
- resolveBaseUrl,
13
12
  resolveDestChain,
14
13
  sourceTokensFromFees,
15
14
  } from '../utils/config'
@@ -24,8 +23,6 @@ import {
24
23
  const STAGE_TO_STATUS: Record<DepositStage, TxnStatus> = {
25
24
  pending: 'Detected',
26
25
  bridging: 'Routing',
27
- // Past deposits use the terminal label — "Received" (plain ink) is the
28
- // active list's arrival state; "Delivered" renders green.
29
26
  completed: 'Delivered',
30
27
  failed: 'Failed',
31
28
  }
@@ -93,7 +90,7 @@ export function PastDeposits({ onSelectDeposit }: PastDepositsProps) {
93
90
 
94
91
  const { deposits, hasLoaded } = useDepositStatus({
95
92
  address,
96
- baseUrl: resolveBaseUrl(config),
93
+ baseUrl: config.baseUrl,
97
94
  })
98
95
 
99
96
  const destChain = resolveDestChain(config)
@@ -1,15 +1,19 @@
1
1
  import {
2
- ArrowCardPair,
3
2
  cn,
4
3
  DataRow,
5
4
  Icon,
6
- InfoCard,
7
5
  ProgressStep,
8
6
  Section,
9
7
  Text,
8
+ TokenSummary,
9
+ Wrapper,
10
10
  } from '@zerodev/react-ui'
11
11
  import { useState } from 'react'
12
- import { FeeBreakdownRows, FeeSummary } from '../components/FeeBreakdown'
12
+ import {
13
+ FeeBreakdownRows,
14
+ FeeDisclosureButton,
15
+ FeeSummary,
16
+ } from '../components/FeeBreakdown'
13
17
  import { FEE_INFO } from '../components/FeeBreakdown/feeInfo'
14
18
  import { useSmartRoutingAddressContext } from '../context/SmartRoutingAddressContext'
15
19
  import { useDepositStatus } from '../hooks/useDepositStatus'
@@ -19,7 +23,6 @@ import type { DepositWithTimestamp } from '../types'
19
23
  import { getTxUrl } from '../utils/chains'
20
24
  import {
21
25
  getSourceTokenSymbol,
22
- resolveBaseUrl,
23
26
  resolveDestChain,
24
27
  sourceTokensFromFees,
25
28
  } from '../utils/config'
@@ -45,7 +48,7 @@ function useLiveDeposit(initial: DepositWithTimestamp): DepositWithTimestamp {
45
48
  addressState.status === 'success' ? addressState.address : undefined
46
49
  const { deposits } = useDepositStatus({
47
50
  address,
48
- baseUrl: resolveBaseUrl(config),
51
+ baseUrl: config.baseUrl,
49
52
  })
50
53
  const targetHash = initial.deposit.transactionHash
51
54
  const live = deposits.find((d) => d.deposit.transactionHash === targetHash) as
@@ -72,9 +75,10 @@ function formatDate(iso?: string): string | null {
72
75
  }
73
76
 
74
77
  /**
75
- * Transaction details view (Figma `17634:105049`) — token hero pair via
76
- * `ArrowCardPair` + `InfoCard`, a "Transaction details" `Section` with the
77
- * route metadata, and a "Transaction Progress" `Section` with the step trail.
78
+ * Transaction details view (Figma `20002:37994`) — delivered-amount hero via
79
+ * `TokenSummary`, a "From" row with the deposited amount, a "Transaction
80
+ * details" `Section` with the route metadata, and a "Transaction Progress"
81
+ * `Section` with the step trail.
78
82
  */
79
83
  export function TransactionDetails({
80
84
  deposit: initialDeposit,
@@ -117,11 +121,11 @@ export function TransactionDetails({
117
121
  const outAmountRaw = execution?.outputAmount
118
122
  const failed = stage === 'failed'
119
123
 
120
- // Headline reads as "how much you sent" — round down so we never overstate
121
- // the deposit. `formatDisplayAmount` (magnitude-aware) also prevents the
124
+ // "From" row amount — round down so we never overstate what was sent.
125
+ // `formatDisplayAmount` (magnitude-aware) also prevents the
122
126
  // 18-decimal fractional tail that `formatTokenAmount` produces for ETH.
123
- const sourceHeadline = feeData
124
- ? `${formatDisplayAmount(amount, feeData.decimal, 'down')} ${sourceSymbol}`
127
+ const sourceAmount = feeData
128
+ ? formatDisplayAmount(amount, feeData.decimal, 'down')
125
129
  : String(amount)
126
130
 
127
131
  // NOTE: `feeData.decimal` is the source token's decimals — the SRA fee
@@ -164,23 +168,36 @@ export function TransactionDetails({
164
168
  // Screen's scroll container can activate scrolling when the fee
165
169
  // breakdown is expanded and content exceeds the viewport.
166
170
  <div className="zd:flex zd:w-full zd:flex-col zd:gap-3 zd:pt-4 zd:pb-6">
167
- <ArrowCardPair
168
- topCard={
169
- <InfoCard
170
- title={sourceHeadline}
171
- {...(sourceTokenLogo && { imageSource: sourceTokenLogo })}
172
- {...(sourceChainLogo && { chainIconUrl: sourceChainLogo })}
173
- />
174
- }
175
- bottomCard={
176
- <InfoCard
177
- title={destHeadline}
178
- {...(destTokenLogo && { imageSource: destTokenLogo })}
179
- {...(destChainLogo && { chainIconUrl: destChainLogo })}
180
- />
181
- }
171
+ {/* Delivered hero (Figma 20002:38000): the received amount headlines
172
+ the card, destination-token tile with chain badge overhanging the
173
+ top. The design's fiat secondary line is omitted — the SRA fee
174
+ estimates carry no USD pricing, and a fabricated conversion would
175
+ be worse than none. */}
176
+ <TokenSummary
177
+ primaryValue={destHeadline}
178
+ {...(destTokenLogo && { tokenLogoUrl: destTokenLogo })}
179
+ {...(destChainLogo && { badgeLogoUrl: destChainLogo })}
182
180
  />
183
181
 
182
+ {/* Deposited-side row (Figma 20002:38012). */}
183
+ {/* py-1.5, not the node's declared p-16: Figma pins this row to
184
+ ~33px total height, which crushes the vertical padding to ~6px —
185
+ honouring p-16 literally renders a ~53px row. */}
186
+ <Wrapper className="zd:flex zd:w-full zd:items-center zd:justify-between zd:rounded-xl zd:px-4 zd:py-1.5">
187
+ <Text className="zd:text-body1">From</Text>
188
+ <span className="zd:flex zd:items-center zd:gap-1">
189
+ <Text className="zd:text-body2">{sourceAmount}</Text>
190
+ {sourceTokenLogo && (
191
+ <img
192
+ src={sourceTokenLogo}
193
+ alt=""
194
+ className="zd:size-4 zd:rounded-full zd:border zd:border-offWhite zd:object-cover"
195
+ />
196
+ )}
197
+ <Text className="zd:text-body2">{sourceSymbol}</Text>
198
+ </span>
199
+ </Wrapper>
200
+
184
201
  <Section title="Transaction details">
185
202
  <DataRow
186
203
  label="From network"
@@ -204,24 +221,19 @@ export function TransactionDetails({
204
221
  {breakdown && (
205
222
  <DataRow
206
223
  label="Total fee"
207
- value={<FeeSummary breakdown={breakdown} />}
208
- info
209
- infoTooltip={FEE_INFO.estimatedFee}
210
- trailing={
211
- <button
212
- type="button"
213
- onClick={() => setFeeOpen((prev) => !prev)}
214
- aria-expanded={feeOpen}
215
- aria-controls={FEE_PANEL_ID}
216
- aria-label={feeOpen ? 'Hide fee details' : 'Show fee details'}
217
- className="zd:inline-flex zd:items-center zd:justify-center zd:cursor-pointer"
224
+ value={
225
+ // The whole value (summary + chevron) toggles the breakdown,
226
+ // not just the arrow.
227
+ <FeeDisclosureButton
228
+ open={feeOpen}
229
+ onToggle={() => setFeeOpen((prev) => !prev)}
230
+ panelId={FEE_PANEL_ID}
218
231
  >
219
- <Icon
220
- name={feeOpen ? 'chevronUp' : 'chevronDown'}
221
- className="zd:w-3.5 zd:h-3.5 zd:text-greyScale"
222
- />
223
- </button>
232
+ <FeeSummary breakdown={breakdown} />
233
+ </FeeDisclosureButton>
224
234
  }
235
+ info
236
+ infoTooltip={FEE_INFO.estimatedFee}
225
237
  />
226
238
  )}
227
239
  {feeOpen && breakdown && (
@@ -301,7 +313,7 @@ function NetworkValue({ name, logoUrl }: { name: string; logoUrl?: string }) {
301
313
  <span className="zd:inline-flex zd:items-center zd:gap-1.5">
302
314
  <Text className="zd:whitespace-nowrap zd:font-medium">{name}</Text>
303
315
  {logoUrl && (
304
- <img src={logoUrl} alt="" className="zd:size-4 zd:rounded-full" />
316
+ <img src={logoUrl} alt="" className="zd:size-4.5 zd:rounded-full" />
305
317
  )}
306
318
  </span>
307
319
  )
@@ -323,11 +335,8 @@ function TxLink({ label, href }: { label: string; href?: string | undefined }) {
323
335
  className="zd:inline-flex zd:items-center zd:gap-1 zd:text-body3 zd:text-greyScale zd:hover:text-solarOrange"
324
336
  >
325
337
  {label}
326
- <Icon
327
- name="export"
328
- className="zd:size-3 zd:text-solarOrange"
329
- aria-hidden
330
- />
338
+ {/* Inherits the link's ink color (Figma 20002:38055) — no orange. */}
339
+ <Icon name="export" className="zd:size-3" aria-hidden />
331
340
  </a>
332
341
  )
333
342
  }
package/src/types.ts CHANGED
@@ -27,13 +27,13 @@ export type SourceToken = {
27
27
 
28
28
  export type SmartRoutingAddressConfig = {
29
29
  /**
30
- * ZeroDev project id; when non-empty it is appended to the server URL
31
- * for every request
30
+ * ZeroDev project id, sent with every address-creation request (the SDK
31
+ * appends it to the server URL)
32
32
  */
33
33
  projectId?: string
34
34
  /** Chain id where funds settle */
35
35
  targetChainId: number
36
- /** Smart routing address version, defaults to the latest stable */
36
+ /** Smart routing address version, defaults to the latest supported */
37
37
  version?: SmartRoutingAddressVersion
38
38
  /**
39
39
  * Destination actions per token type. When omitted, funds are simply
@@ -44,10 +44,7 @@ export type SmartRoutingAddressConfig = {
44
44
  * Max slippage in basis points (50 = 0.5%).
45
45
  */
46
46
  slippage: number
47
- /**
48
- * Override the smart routing address server root URL; the projectId is
49
- * appended to it
50
- */
47
+ /** Override the smart routing address server root URL */
51
48
  baseUrl?: string
52
49
  }
53
50
 
@@ -1,13 +1,12 @@
1
1
  import type {
2
- CreateSmartRoutingAddressParams,
2
+ CALL,
3
3
  SmartRoutingAddressVersion,
4
4
  TOKEN_TYPE,
5
5
  } from '@zerodev/smart-routing-address'
6
6
  import {
7
7
  createCall,
8
8
  FLEX,
9
- SMART_ROUTING_ADDRESS_SERVER_URL,
10
- SMART_ROUTING_ADDRESS_V0_2_1,
9
+ SMART_ROUTING_ADDRESS_V1_0_0,
11
10
  SUPPORTED_TOKENS,
12
11
  } from '@zerodev/smart-routing-address'
13
12
  import { type Address, type Chain, erc20Abi } from 'viem'
@@ -23,21 +22,7 @@ import { tokenAddressMatches } from './fees'
23
22
  export function resolveVersion(
24
23
  config: SmartRoutingAddressConfig,
25
24
  ): SmartRoutingAddressVersion {
26
- return config.version ?? SMART_ROUTING_ADDRESS_V0_2_1
27
- }
28
-
29
- /**
30
- * Server URL for all smart routing address requests: the server root
31
- * (default or `config.baseUrl`) with the ZeroDev project id appended.
32
- * Without a project id the URL is only overridden when `config.baseUrl`
33
- * is set; undefined leaves the SDK default in place.
34
- */
35
- export function resolveBaseUrl(
36
- config: SmartRoutingAddressConfig,
37
- ): string | undefined {
38
- if (!config.projectId) return config.baseUrl
39
- const root = config.baseUrl ?? SMART_ROUTING_ADDRESS_SERVER_URL
40
- return `${root.replace(/\/+$/, '')}/${config.projectId}`
25
+ return config.version ?? SMART_ROUTING_ADDRESS_V1_0_0
41
26
  }
42
27
 
43
28
  export function resolveDashboardUrl(address?: string): string {
@@ -102,11 +87,16 @@ function uniqueTokenTypes(sources: SourceToken[]): TOKEN_TYPE[] {
102
87
  * Destination actions for every resolved source token type: ERC-20 deposits
103
88
  * are transferred to the recipient and native deposits are forwarded as
104
89
  * value. FLEX placeholders are resolved by the server per deposit.
90
+ *
91
+ * v0.x managers additionally run `fallBack` when `action` reverts, so legacy
92
+ * versions get the same calls as the fallback; v1 managers have no fallback
93
+ * and reject the field.
105
94
  */
106
95
  export function resolveActions(
107
96
  config: SmartRoutingAddressConfig,
108
97
  recipient: Address,
109
- ): CreateSmartRoutingAddressParams['actions'] {
98
+ version: SmartRoutingAddressVersion,
99
+ ): { [key in TOKEN_TYPE]?: { action: CALL[]; fallBack?: CALL[] } } {
110
100
  const erc20Call = createCall({
111
101
  target: FLEX.TOKEN_ADDRESS,
112
102
  value: 0n,
@@ -118,15 +108,13 @@ export function resolveActions(
118
108
  target: recipient,
119
109
  value: FLEX.NATIVE_AMOUNT,
120
110
  })
111
+ const legacy = version !== SMART_ROUTING_ADDRESS_V1_0_0
121
112
 
122
113
  return Object.fromEntries(
123
- uniqueTokenTypes(resolveSourceTokens(config)).map((tokenType) => [
124
- tokenType,
125
- {
126
- action: tokenType === 'NATIVE' ? [nativeCall] : [erc20Call],
127
- fallBack: tokenType === 'NATIVE' ? [nativeCall] : [erc20Call],
128
- },
129
- ]),
114
+ uniqueTokenTypes(resolveSourceTokens(config)).map((tokenType) => {
115
+ const action = tokenType === 'NATIVE' ? [nativeCall] : [erc20Call]
116
+ return [tokenType, { action, ...(legacy && { fallBack: action }) }]
117
+ }),
130
118
  )
131
119
  }
132
120