Skip to content

Commit 9b8105a

Browse files
committed
fix(app): BNB quote token and error handling
Signed-off-by: Eric Hegnes <[email protected]>
1 parent bcebe12 commit 9b8105a

File tree

2 files changed

+88
-45
lines changed

2 files changed

+88
-45
lines changed

app2/src/lib/transfer/shared/data/transfer-data.svelte.ts

Lines changed: 1 addition & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -308,21 +308,7 @@ export class TransferData {
308308
),
309309
)
310310

311-
version = $derived(pipe(
312-
this.channel,
313-
Option.tap((x) => {
314-
return Option.some(x)
315-
}),
316-
Option.map(Struct.get("tags")),
317-
Option.map(A.contains<"canonical" | "tokenorder-v2">("tokenorder-v2")),
318-
Option.map(B.match({
319-
onTrue: constant(2 as const),
320-
onFalse: constant(1 as const),
321-
})),
322-
Option.tap((x) => {
323-
return Option.some(x)
324-
}),
325-
))
311+
version = Option.some(2)
326312

327313
baseTokenBalance = $derived(
328314
Option.all([this.baseToken, this.sortedBalances]).pipe(

app2/src/lib/transfer/shared/services/filling/create-context.ts

Lines changed: 87 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,12 @@ import type {
1010
TokenRawAmount,
1111
UniversalChainId,
1212
} from "@unionlabs/sdk/schema"
13-
import { Effect, Match, Option, ParseResult, pipe } from "effect"
13+
import { Effect, Either, flow, Match, Option, ParseResult, pipe } from "effect"
1414
import * as A from "effect/Array"
1515
import type { NoSuchElementException, UnknownException } from "effect/Cause"
1616
import * as S from "effect/Schema"
1717
import { fromHex, isHex } from "viem"
18+
import { GenericFlowError } from "../../errors"
1819
import type { TransferArgs } from "./check-filling"
1920

2021
export type Intent = {
@@ -51,17 +52,35 @@ export const createContext = Effect.fn((
5152
args: TransferArgs,
5253
): Effect.Effect<
5354
TransferContext,
54-
NoSuchElementException | ParseResult.ParseError | UnknownException,
55+
ParseResult.ParseError | GenericFlowError | UnknownException | NoSuchElementException,
5556
never
5657
> =>
5758
Effect.gen(function*() {
5859
console.debug("[createContext] args:", args)
5960

61+
const baseAmount = yield* parseBaseAmount(args.baseAmount).pipe(
62+
Effect.mapError((cause) =>
63+
new GenericFlowError({
64+
message: "Could not parse base amount",
65+
cause,
66+
})
67+
),
68+
)
69+
70+
const quoteAmount = yield* parseBaseAmount(args.quoteAmount).pipe(
71+
Effect.mapError((cause) =>
72+
new GenericFlowError({
73+
message: "Could not parse quote amount",
74+
cause,
75+
})
76+
),
77+
)
78+
6079
const sendOrder = yield* TokenOrder.make({
61-
baseAmount: Option.getOrThrow(parseBaseAmount(args.baseAmount)),
80+
baseAmount,
6281
baseToken: args.baseToken,
6382
quoteToken: args.quoteToken,
64-
quoteAmount: Option.getOrThrow(parseBaseAmount(args.quoteAmount)),
83+
quoteAmount,
6584
destination: args.destinationChain,
6685
receiver: args.receiver,
6786
sender: args.sender,
@@ -78,19 +97,39 @@ export const createContext = Effect.fn((
7897
})
7998

8099
// on destination chain tokens, find wrappings[] such that one exists where unwrapped_denom matches basetoken and unwrapped_chain and wrapped_chain universal ids match
81-
const encodedFeeBaseToken = S.encodeSync(Token.AnyFromEncoded(args.sourceChain.rpc_type))(
100+
const encodedFeeBaseToken = yield* pipe(
82101
args.fee.baseToken,
102+
S.encode(Token.AnyFromEncoded(args.sourceChain.rpc_type)),
103+
Effect.mapError((cause) =>
104+
new GenericFlowError({
105+
message: "Could not base token",
106+
cause,
107+
})
108+
),
109+
)
110+
111+
const shouldIncludeFees = shouldChargeFees(
112+
args.fee,
113+
uiStore.edition,
114+
args.sourceChain,
115+
args.destinationChain,
83116
)
84117

85-
const shouldIncludeFees = shouldChargeFees(args.fee, uiStore.edition, args.sourceChain)
118+
console.log({ shouldIncludeFees })
86119

87120
const produceBatch = Effect.gen(function*() {
88121
if (shouldIncludeFees) {
89-
const feeQuoteToken = yield* maybeFeeQuoteToken.pipe(
90-
Option.orElse(() =>
122+
if (args.baseToken.address === "au") {
123+
return args.quoteToken
124+
}
125+
const feeQuoteToken = yield* pipe(
126+
maybeFeeQuoteToken,
127+
Either.fromOption(() => "No fee quote token"),
128+
Either.orElse(() =>
91129
pipe(
92130
tokensStore.getData(args.destinationChain.universal_chain_id),
93-
Option.flatMap(
131+
Either.fromOption(() => "No matching token in token store"),
132+
Either.flatMap(flow(
94133
A.findFirst((token) =>
95134
A.filter(token.wrapping, (x) =>
96135
x.unwrapped_denom === encodedFeeBaseToken
@@ -100,20 +139,22 @@ export const createContext = Effect.fn((
100139
.length
101140
=== 1
102141
),
103-
),
104-
Option.map(x => x.denom),
105-
Option.flatMap((raw) =>
106-
S.decodeOption(Token.AnyFromEncoded(args.destinationChain.rpc_type))(raw)
142+
Either.fromOption(() =>
143+
`No quote token wrapping found for ${args.destinationChain.universal_chain_id} given ${args.fee.baseToken}`
144+
),
145+
)),
146+
Either.map(x => x.denom),
147+
Either.flatMap((raw) =>
148+
S.decodeEither(Token.AnyFromEncoded(args.destinationChain.rpc_type))(raw)
107149
),
108150
)
109151
),
110-
Option.orElse(() => {
111-
if (args.baseToken.address === "au") {
112-
return Option.some(args.quoteToken)
113-
}
114-
console.error("Could not determine fee quote token.")
115-
return Option.none()
116-
}),
152+
Effect.mapError((cause) =>
153+
new GenericFlowError({
154+
message: "Could not determine fee quote token",
155+
cause,
156+
})
157+
),
117158
)
118159

119160
const feeOrder = yield* TokenOrder.make({
@@ -130,7 +171,8 @@ export const createContext = Effect.fn((
130171
version: args.version,
131172
})
132173

133-
return Batch.make([sendOrder, feeOrder]).pipe(
174+
return pipe(
175+
Batch.make([sendOrder, feeOrder]),
134176
Batch.optimize,
135177
)
136178
} else {
@@ -150,19 +192,17 @@ export const createContext = Effect.fn((
150192
Option.some,
151193
)
152194

153-
const ctx = yield* parseBaseAmount(args.baseAmount).pipe(
154-
Option.flatMap((baseAmount) => {
155-
const intents = createIntents(args, baseAmount)
156-
157-
return intents.length > 0
195+
const ctx = yield* pipe(
196+
createIntents(args, baseAmount),
197+
(intents) =>
198+
intents.length > 0
158199
? Option.some({
159200
intents,
160201
allowances: Option.none(),
161202
request: Option.none(),
162203
message: Option.none(),
163204
})
164-
: Option.none()
165-
}),
205+
: Option.none(),
166206
)
167207

168208
return {
@@ -173,7 +213,12 @@ export const createContext = Effect.fn((
173213
)
174214

175215
const createIntents = (args: TransferArgs, baseAmount: TokenRawAmount): Intent[] => {
176-
const shouldIncludeFees = shouldChargeFees(args.fee, uiStore.edition, args.sourceChain)
216+
const shouldIncludeFees = shouldChargeFees(
217+
args.fee,
218+
uiStore.edition,
219+
args.sourceChain,
220+
args.destinationChain,
221+
)
177222
const baseIntent = createBaseIntent(args, baseAmount)
178223

179224
return Match.value(args.sourceChain.rpc_type).pipe(
@@ -241,13 +286,25 @@ const createBaseIntent = (
241286
})
242287

243288
// Fee strategy: BTC edition only charges fees when going FROM Babylon
244-
const shouldChargeFees = (fee: FeeIntent, edition: string, sourceChain: Chain): boolean => {
289+
const shouldChargeFees = (
290+
fee: FeeIntent,
291+
edition: string,
292+
sourceChain: Chain,
293+
destinationChain: Chain,
294+
): boolean => {
245295
if (fee.baseAmount === 0n) {
246296
return false
247297
}
248298
if (sourceChain.testnet) {
249299
return true
250300
}
301+
// skip fees babylon to bsc for now
302+
if (
303+
destinationChain.universal_chain_id === "bsc.56"
304+
&& sourceChain.universal_chain_id === "babylon.bbn-1"
305+
) {
306+
return false
307+
}
251308
return sourceChain.universal_chain_id === "babylon.bbn-1"
252309
}
253310

0 commit comments

Comments
 (0)