Skip to content

Commit 1796364

Browse files
authored
Revert "[Swap V2] - Fixes and Updates (#4332)"
This reverts commit 09c0c4c.
1 parent 09c0c4c commit 1796364

File tree

12 files changed

+127
-161
lines changed

12 files changed

+127
-161
lines changed

packages/yoroi-extension/app/UI/features/swap-new/common/components/AssetInput.tsx

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -73,18 +73,27 @@ export const AssetInput: React.FC<AssetInputProps> = ({ direction, onAssetSelect
7373
}
7474

7575
const assetInputName = React.useMemo(() => {
76-
if (direction === ASSET_DIRECTION_OUT && !touched) {
77-
return 'Select token';
76+
if (direction === ASSET_DIRECTION_IN) {
77+
return tokenInputInfo?.ticker ? tokenInputInfo?.name : primaryTokenInfo.name;
7878
}
79-
80-
return tokenInput.tokenId === '.' || tokenInput.tokenId === ''
81-
? primaryTokenInfo.name
82-
: (tokenInputInfo?.ticker ?? tokenInputInfo?.name);
83-
}, [direction, tokenInputInfo, swapForm.tokenInInput.tokenId, swapForm.tokenOutInput.tokenId]);
79+
if (direction === ASSET_DIRECTION_OUT) {
80+
if (!touched) {
81+
return 'Select token';
82+
}
83+
return tokenInput.tokenId === '.' ? primaryTokenInfo.name : (tokenInputInfo?.ticker ?? tokenInputInfo?.name);
84+
}
85+
return undefined;
86+
}, [direction, tokenInputInfo]);
8487

8588
const AssetIdForIcon = React.useMemo(() => {
86-
return tokenInput.tokenId === '.' || tokenInput.tokenId === '' ? '.' : tokenInputInfo?.id;
87-
}, [direction, tokenInputInfo, swapForm.tokenInInput.tokenId, swapForm.tokenOutInput.tokenId]);
89+
if (direction === ASSET_DIRECTION_IN) {
90+
return tokenInput.tokenId ?? tokenInputInfo?.id;
91+
}
92+
if (direction === ASSET_DIRECTION_OUT) {
93+
return tokenInput.tokenId === '.' ? primaryTokenInfo.id : tokenInputInfo?.id;
94+
}
95+
return undefined;
96+
}, [direction, tokenInputInfo, tokenInput]);
8897

8998
const focusInput = () => {
9099
if (inputRef?.current) {
@@ -211,7 +220,6 @@ const Wrapper = styled(Box, {
211220
}`,
212221
backgroundColor: direction === ASSET_DIRECTION_IN ? 'transparent' : theme.palette.ds.bg_color_contrast_min,
213222
height: '132px',
214-
width: '506px',
215223

216224
'&:hover': {
217225
borderColor: !hasError && theme.palette.ds.el_gray_max,

packages/yoroi-extension/app/UI/features/swap-new/common/components/Modals/SettingsModalContent.tsx

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,14 +32,11 @@ export const SettingsModalContent = () => {
3232
};
3333

3434
const applyChanges = async () => {
35-
await swapForm.action({
36-
type: SwapActionType.ProtocolSelected,
37-
value: routingPreference === DEX_ROUTING.BOTH ? DEX_ROUTING.AUTO : routingPreference,
38-
});
35+
await swapForm.action({ type: SwapActionType.ProtocolSelected, value: routingPreference });
3936
await swapForm.action({ type: SwapActionType.SlippageInputChanged, value: Number(selectedSlippage) });
4037
await swapManager.assignSettings({
4138
slippage: Number(selectedSlippage),
42-
routingPreference: routingPreference === DEX_ROUTING.BOTH ? DEX_ROUTING.AUTO : routingPreference,
39+
routingPreference,
4340
});
4441
closeModal();
4542
};

packages/yoroi-extension/app/UI/features/swap-new/common/constants.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ export const MARKET_ORDER = 'market';
1111
export const LIMIT_ORDER = 'limit';
1212

1313
export const undefinedToken: Portfolio.Token.Id = '.unknown';
14-
export const USDA_TOKEN_ID = 'fe7c786ab321f41c654ef6c1af7b3250a613c24e4213e0425a7ae456.55534441';
1514

1615
export const DEX_ROUTING = {
1716
AUTO: 'auto',

packages/yoroi-extension/app/UI/features/swap-new/common/helpers.ts

Lines changed: 73 additions & 107 deletions
Original file line numberDiff line numberDiff line change
@@ -1,121 +1,87 @@
11
import { RustModule } from '../../../../api/ada/lib/cardanoCrypto/rustLoader';
22
export const normalizeTokenId = (id?: string | null) => (id === '' ? '.' : id);
33

4-
type WalletUtxo = {
5-
address: string; // raw address bytes (hex)
6-
output: {
7-
Transaction: { Hash: string }; // 64-hex
8-
UtxoTransactionOutput: { OutputIndex: number };
9-
tokens?: Array<{
10-
Token: {
11-
Identifier: string; // '.' for ADA, or `${policyId}.${assetNameHex}`
12-
Metadata: { ticker?: string; policyId?: string; assetName?: string };
13-
};
14-
TokenList: { Amount: string }; // decimal string
15-
}>;
16-
inlineDatumCborHex?: string;
17-
datumHashHex?: string;
18-
scriptRefCborHex?: string;
19-
};
20-
};
4+
export const useGetInputs = (walletUtxos: any[]) => {
5+
const getInputs = async (amounts: { [tokenId: string]: string }) => {
6+
try {
7+
const tokenId = Object.keys(amounts)[0];
8+
if (tokenId === undefined) {
9+
throw new Error('No tokenId provided in amounts');
10+
}
11+
const requiredAmount = BigInt(Number(amounts[tokenId]));
12+
13+
const matching = walletUtxos
14+
.map(utxo => {
15+
const token = utxo.output.tokens.find(t => {
16+
return tokenId === '.' ? t.Token.Metadata.ticker === 'ADA' : t.Token.Identifier === tokenId;
17+
});
18+
19+
return token
20+
? {
21+
utxo,
22+
amount: BigInt(token.TokenList.Amount),
23+
}
24+
: null;
25+
})
26+
.filter(Boolean)
27+
.sort((a, b) => (a!.amount > b!.amount ? -1 : 1)) as {
28+
utxo: any;
29+
amount: bigint;
30+
}[];
31+
32+
const selected: any[] = [];
33+
let total = BigInt(0);
34+
35+
for (const { utxo, amount } of matching) {
36+
selected.push(utxo);
37+
total += amount;
38+
if (total >= requiredAmount) break;
39+
}
2140

22-
const isHex = (s: string) => /^[0-9a-f]*$/i.test(s);
23-
const isHex64 = (s: string) => /^[0-9a-f]{64}$/i.test(s);
24-
const hexToBytes = (hex: string): Uint8Array => {
25-
if (!isHex(hex) || hex.length % 2 !== 0) throw new Error('Invalid hex');
26-
const out = new Uint8Array(hex.length / 2);
27-
for (let i = 0; i < out.length; i++) out[i] = parseInt(hex.substr(i * 2, 2), 16);
28-
return out;
29-
};
30-
const bytesToHex = (bytes: Uint8Array): string => {
31-
let hex = '';
32-
// @ts-ignore
33-
for (let i = 0; i < bytes.length; i++) hex += bytes[i].toString(16).padStart(2, '0');
34-
return hex;
35-
};
36-
const looksLikeTUSO = (hex: string) =>
37-
typeof hex === 'string' && /^[0-9a-f]+$/i.test(hex) && hex.toLowerCase().startsWith('82825820'); // 82 [input,output] / 82 [hash,index] / 58 20 (32-byte hash)
38-
39-
export const useGetInputs = (walletUtxos: WalletUtxo[]) => {
40-
// encode one UTxO -> CBOR hex TUSO
41-
const encodeUtxo = (u: WalletUtxo): string => {
42-
const { WalletV4 } = RustModule;
43-
44-
const input = WalletV4.TransactionInput.new(
45-
WalletV4.TransactionHash.from_hex(u.output.Transaction.Hash),
46-
u.output.UtxoTransactionOutput.OutputIndex
47-
);
48-
49-
const addr = WalletV4.Address.from_bytes(hexToBytes(u.address));
50-
51-
const value = WalletV4.Value.new(WalletV4.BigNum.from_str('0'));
52-
const ma = WalletV4.MultiAsset.new();
53-
let lovelaceSet = false;
54-
55-
for (const t of u.output.tokens ?? []) {
56-
const amt = WalletV4.BigNum.from_str(t.TokenList.Amount);
57-
const isAda = t.Token.Identifier === '.' || (t.Token.Metadata?.ticker ?? '').toUpperCase() === 'ADA';
58-
59-
if (isAda) {
60-
value.set_coin(amt);
61-
lovelaceSet = true;
62-
} else {
63-
const policyId = t.Token.Metadata?.policyId;
64-
const assetNameHex = t.Token.Metadata?.assetName;
65-
if (!policyId || !assetNameHex) continue;
66-
const policy = WalletV4.ScriptHash.from_hex(policyId);
67-
const assets = ma.get(policy) ?? WalletV4.Assets.new();
68-
assets.insert(WalletV4.AssetName.new(hexToBytes(assetNameHex)), amt);
69-
ma.insert(policy, assets);
41+
if (total < requiredAmount) {
42+
throw new Error('Not enough balance');
7043
}
71-
}
7244

73-
if (!lovelaceSet) value.set_coin(WalletV4.BigNum.from_str('0'));
74-
if (ma.len() > 0) value.set_multiasset(ma);
45+
const inputs = await Promise.all(
46+
selected.map(async u => {
47+
const txHash = u.output.Transaction.Hash;
48+
const index = u.output.UtxoTransactionOutput.OutputIndex;
7549

76-
const out = WalletV4.TransactionOutput.new(addr, value);
50+
const receiver = await RustModule.WalletV4.Address.from_bytes(Buffer.from(u.address, 'hex')).to_bech32();
7751

78-
if (u.output.inlineDatumCborHex) {
79-
out.set_datum(WalletV4.Datum.new_data(WalletV4.PlutusData.from_bytes(hexToBytes(u.output.inlineDatumCborHex))));
80-
} else if (u.output.datumHashHex) {
81-
out.set_datum(WalletV4.Datum.new_data_hash(WalletV4.DataHash.from_bytes(hexToBytes(u.output.datumHashHex))));
82-
}
83-
if (u.output.scriptRefCborHex) {
84-
out.set_script_ref(WalletV4.ScriptRef.from_bytes(hexToBytes(u.output.scriptRefCborHex)));
85-
}
52+
const input = RustModule.WalletV4.TransactionInput.new(RustModule.WalletV4.TransactionHash.from_hex(txHash), index);
8653

87-
const tuso = WalletV4.TransactionUnspentOutput.new(input, out);
88-
const hex = bytesToHex(tuso.to_bytes());
89-
if (!looksLikeTUSO(hex)) throw new Error(`Not a full TransactionUnspentOutput: ${hex.slice(0, 10)}…`);
90-
return hex;
91-
};
54+
const value = RustModule.WalletV4.Value.new(RustModule.WalletV4.BigNum.from_str('0'));
9255

93-
// dedupe + validate by (txHash#index)
94-
const sanitize = (list: WalletUtxo[]) => {
95-
const seen = new Set<string>();
96-
const out: WalletUtxo[] = [];
97-
for (const u of list) {
98-
const txh = u.output?.Transaction?.Hash;
99-
const idx = u.output?.UtxoTransactionOutput?.OutputIndex;
100-
if (!txh || typeof idx !== 'number' || !isHex64(txh)) continue;
101-
const key = `${txh}#${idx}`;
102-
if (seen.has(key)) continue;
103-
seen.add(key);
104-
out.push(u);
105-
}
106-
// stable order
107-
out.sort(
108-
(a, b) =>
109-
a.output.Transaction.Hash.localeCompare(b.output.Transaction.Hash) ||
110-
a.output.UtxoTransactionOutput.OutputIndex - b.output.UtxoTransactionOutput.OutputIndex
111-
);
112-
return out;
113-
};
56+
for (const token of u.output.tokens) {
57+
const amt = RustModule.WalletV4.BigNum.from_str(token.TokenList.Amount);
58+
59+
if (token.Token.Metadata.ticker === 'ADA') {
60+
value.set_coin(amt);
61+
} else {
62+
const policyId = RustModule.WalletV4.ScriptHash.from_hex(token.Token.Metadata.policyId);
63+
const assetName = RustModule.WalletV4.AssetName.new(Buffer.from(token.Token.Metadata.assetName, 'hex'));
11464

115-
// returns ALL UTXOs as TUSO CBOR hex
116-
const getInputs = async (): Promise<string[]> => {
117-
const utxos = sanitize(walletUtxos);
118-
return utxos.map(encodeUtxo);
65+
const multiasset = value.multiasset() || RustModule.WalletV4.MultiAsset.new();
66+
const assets = multiasset.get(policyId) || RustModule.WalletV4.Assets.new();
67+
assets.insert(assetName, amt);
68+
multiasset.insert(policyId, assets);
69+
value.set_multiasset(multiasset);
70+
}
71+
}
72+
73+
const output = RustModule.WalletV4.TransactionOutput.new(RustModule.WalletV4.Address.from_bech32(receiver), value);
74+
75+
const utxo = RustModule.WalletV4.TransactionUnspentOutput.new(input, output);
76+
return Buffer.from(utxo.to_bytes()).toString('hex');
77+
})
78+
);
79+
80+
return inputs;
81+
} catch {
82+
console.warn('Failed to get inputs');
83+
return [];
84+
}
11985
};
12086

12187
return { getInputs };

packages/yoroi-extension/app/UI/features/swap-new/common/hooks/useTokensInfo.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,10 @@ export const useSyncedTokenInfos = ({
2222
queryKey: ['syncedTokenInfos', networkId, primaryTokenInfo.id, ...excludedTokens],
2323

2424
queryFn: async () => {
25+
// Hardcoded muesliswap because dexhunter is broken at the moment
26+
await swapManager.assignSettings({
27+
routingPreference: 'muesliswap',
28+
});
2529
const res = await swapManager.api.tokens();
2630
if (!isRight(res)) return { tokenIds: [], tokenInfosArray: [] };
2731

packages/yoroi-extension/app/UI/features/swap-new/module/SwapContextProvider.tsx

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ import { tokenManagers } from '../../portfolio/common/helpers/build-token-manage
2222
import { useSyncedTokenInfos } from '../common/hooks/useTokensInfo';
2323
import { isLeft, isRight } from '@yoroi/common';
2424
import { useGetInputs } from '../common/helpers';
25-
import { ASSET_DIRECTION_IN, USDA_TOKEN_ID } from '../common/constants';
25+
import { ASSET_DIRECTION_IN } from '../common/constants';
2626

2727
export const convertBech32ToHex = async (bech32Address: string) => {
2828
return await RustModule.WalletV4.Address.from_bech32(bech32Address).to_hex();
@@ -49,6 +49,7 @@ export const SwapContextProvider = ({ children, currentWallet, stores }: any) =>
4949
const tokenInInputRef = useRef<HTMLInputElement | null>(null);
5050

5151
const { getInputs } = useGetInputs(selectedWallet?.utxos || []);
52+
5253
const [state, action] = useReducer(swapReducer, defaultState);
5354

5455
useEffect(() => {
@@ -236,8 +237,15 @@ export const SwapContextProvider = ({ children, currentWallet, stores }: any) =>
236237

237238
const create = useCallback(async () => {
238239
if (state.tokenInInput.tokenId === undefined || state.tokenOutInput.tokenId === undefined) return;
240+
239241
setIsCreateOrderLoading(true);
240-
const inputs = await getInputs();
242+
243+
const tokenInInfo = tokenInfos.get(state.tokenInInput.tokenId);
244+
const quantityIn =
245+
Number(state.tokenInInput.value) *
246+
10 ** (state.tokenInInput.tokenId === '.' ? primaryTokenInfo.decimals : tokenInInfo?.decimals);
247+
const amountsIn = { [state.tokenInInput.tokenId]: String(quantityIn) };
248+
const inputs = await getInputs(amountsIn);
241249

242250
swapManager.api
243251
.create({
@@ -591,7 +599,7 @@ const defaultState: SwapState = Object.freeze({
591599
},
592600
tokenOutInput: {
593601
isTouched: true,
594-
tokenId: USDA_TOKEN_ID,
602+
tokenId: undefined,
595603
disabled: false,
596604
error: null,
597605
value: '',

packages/yoroi-extension/app/UI/features/swap-new/useCases/SwapOrders.tsx/SwapOrders.tsx

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -241,18 +241,12 @@ const OrderCancelation = ({ order }: { order: Swap.Order }) => {
241241
try {
242242
startLoadingTxReview();
243243
try {
244-
const { signedTxHex: signedCancelTx } = await stores.transactionProcessingStore.adaSignTransactionHexFromWallet({
244+
await stores.transactionProcessingStore.adaSignTransactionHexFromWallet({
245245
wallet,
246246
transactionHex: cancelTxCbor,
247247
password: passswordInput,
248248
});
249249

250-
const signedTransactionHexes: any = [signedCancelTx];
251-
await stores.substores.ada.swapStore.executeTransactionHexes({
252-
wallet,
253-
signedTransactionHexes,
254-
});
255-
256250
showTxResultModal(TransactionResult.SUCCESS);
257251
} catch (error) {
258252
console.warn('Failed to submit transaction', error);

packages/yoroi-extension/app/UI/features/transaction-review/common/TokenItem.tsx

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -39,21 +39,15 @@ const getTokenName = (tokenInfo: any): string => {
3939
export const TokenItem: React.FC<TokenItemProps> = ({ isSent = true, isPrimary, tokenInfo, quantity }: TokenItemProps) => {
4040
const decimals = getDecimals(tokenInfo);
4141
const tokenName = getTokenName(tokenInfo);
42+
4243
const value = new BigNumber(quantity).shiftedBy(-decimals).toString();
4344
if (isSent) {
4445
const primaryColor = isPrimary ? 'ds.white_static' : 'ds.text_primary_medium';
4546
const primaryBackground = isPrimary ? 'ds.primary_500' : 'ds.primary_100';
4647
return (
47-
<Box
48-
sx={{
49-
padding: '4px 12px',
50-
backgroundColor: primaryBackground,
51-
borderRadius: '8px',
52-
flexWrap: 'nowrap',
53-
}}
54-
>
48+
<Box sx={{ padding: '4px 12px', backgroundColor: primaryBackground, borderRadius: '8px', flexWrap: 'nowrap' }}>
5549
<Typography variant="body1" color={primaryColor}>
56-
{value} {tokenName || tokenInfo?.ticker}
50+
{value} {tokenName}
5751
</Typography>
5852
</Box>
5953
);
@@ -64,7 +58,7 @@ export const TokenItem: React.FC<TokenItemProps> = ({ isSent = true, isPrimary,
6458
return (
6559
<Box sx={{ padding: '4px 12px', backgroundColor: primaryBackground, borderRadius: '8px', flexWrap: 'nowrap' }}>
6660
<Typography variant="body1" color={primaryColor}>
67-
{value} {tokenName || tokenInfo?.ticker}
61+
{value} {tokenName}
6862
</Typography>
6963
</Box>
7064
);

packages/yoroi-extension/app/UI/features/transaction-review/common/hooks/useFormattedTx.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ export const useFormattedTx = (data: TransactionBody): FormattedTx => {
4141

4242
const formatInputs = (inputUtxos, allAssetList, networkId, primaryTokenInfo, walletAddresses): any => {
4343
return inputUtxos.map(utxo => {
44-
const address = utxo?.receiver || utxo?.address;
44+
const address = utxo?.receiver;
4545
const { resolvedAddress, paymentCredKind } = resolveAddress(address);
4646

4747
const rewardAddress = address !== null && paymentCredKind === CredKind.Key ? deriveAddress(address, networkId) : null;

packages/yoroi-extension/app/UI/features/transaction-review/useCases/ReviewTx/ReferenceInputs/ReferenceInputsTab.tsx

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,7 @@ import { Inputs } from '../UTxOs/UTxOsTab';
44
export const ReferenceInputsTab = ({ referenceInputs }) => {
55
return (
66
<Stack p="24px">
7-
<Inputs
8-
key={`${referenceInputs.address}-${referenceInputs.tx_hash}-${referenceInputs.tx_index}`}
9-
inputs={referenceInputs}
10-
/>
7+
<Inputs key={`${referenceInputs.address}-${referenceInputs.txHash}-${referenceInputs.txIndex}`} inputs={referenceInputs} />
118
</Stack>
129
);
1310
};

0 commit comments

Comments
 (0)