From e4635d9d830cea02fb562cae0c7b3bacbf7220c0 Mon Sep 17 00:00:00 2001 From: Jamie Harding Date: Fri, 20 Dec 2024 14:24:19 +0100 Subject: [PATCH 001/142] add dropdowns and buttons --- .../deployment/DepositButtons.svelte | 63 ++++ .../deployment/DepositDropdown.svelte | 62 ++++ .../deployment/FieldDefinitionButtons.svelte | 71 +++++ .../deployment/FieldDefinitionDropdown.svelte | 64 ++++ packages/ui-components/src/lib/index.ts | 4 + .../webapp/src/routes/deployment/+page.svelte | 148 ++------- .../src/routes/deployment/new/+page.svelte | 300 ++++++++++++++++++ 7 files changed, 596 insertions(+), 116 deletions(-) create mode 100644 packages/ui-components/src/lib/components/deployment/DepositButtons.svelte create mode 100644 packages/ui-components/src/lib/components/deployment/DepositDropdown.svelte create mode 100644 packages/ui-components/src/lib/components/deployment/FieldDefinitionButtons.svelte create mode 100644 packages/ui-components/src/lib/components/deployment/FieldDefinitionDropdown.svelte create mode 100644 packages/webapp/src/routes/deployment/new/+page.svelte diff --git a/packages/ui-components/src/lib/components/deployment/DepositButtons.svelte b/packages/ui-components/src/lib/components/deployment/DepositButtons.svelte new file mode 100644 index 000000000..6a0ad1d54 --- /dev/null +++ b/packages/ui-components/src/lib/components/deployment/DepositButtons.svelte @@ -0,0 +1,63 @@ + + +
+ + +
+ {#each deposit.presets as preset} + + {/each} + +
+ + {#if !gui?.isDepositPreset(deposit.token_name)} + { + if (currentTarget instanceof HTMLInputElement) { + gui?.saveDeposit(deposit.token_name, currentTarget.value); + } + }} + /> + {/if} +
diff --git a/packages/ui-components/src/lib/components/deployment/DepositDropdown.svelte b/packages/ui-components/src/lib/components/deployment/DepositDropdown.svelte new file mode 100644 index 000000000..5d04db276 --- /dev/null +++ b/packages/ui-components/src/lib/components/deployment/DepositDropdown.svelte @@ -0,0 +1,62 @@ + + +
+ + + [ + preset, + { + label: preset + } + ]) + ), + ...{ custom: { label: 'Custom value' } } + }} + on:change={({ detail }) => { + gui?.saveDeposit(deposit.token_name, detail.value === 'custom' ? '' : detail.value || ''); + gui = gui; + }} + > + + {#if selectedRef === undefined} + Choose deposit amount + {:else if selectedOption?.label} + {selectedOption.label} + {:else} + {selectedRef} + {/if} + + + +
+
{option.label ? option.label : ref}
+
+
+
+ + {#if gui?.isDepositPreset(deposit.token_name) === false} + { + if (currentTarget instanceof HTMLInputElement) { + gui?.saveDeposit(deposit.token_name, currentTarget.value); + } + }} + /> + {/if} +
diff --git a/packages/ui-components/src/lib/components/deployment/FieldDefinitionButtons.svelte b/packages/ui-components/src/lib/components/deployment/FieldDefinitionButtons.svelte new file mode 100644 index 000000000..b2025e7ba --- /dev/null +++ b/packages/ui-components/src/lib/components/deployment/FieldDefinitionButtons.svelte @@ -0,0 +1,71 @@ + + +
+ + +
+ {#if fieldDefinition.presets} + {#each fieldDefinition.presets as preset} + + {/each} + {/if} + +
+ + {#if !gui?.isFieldPreset(fieldDefinition.binding)} + { + if (currentTarget instanceof HTMLInputElement) { + gui?.saveFieldValue(fieldDefinition.binding, { + isPreset: false, + value: currentTarget.value + }); + } + }} + /> + {/if} +
diff --git a/packages/ui-components/src/lib/components/deployment/FieldDefinitionDropdown.svelte b/packages/ui-components/src/lib/components/deployment/FieldDefinitionDropdown.svelte new file mode 100644 index 000000000..aae92b7e5 --- /dev/null +++ b/packages/ui-components/src/lib/components/deployment/FieldDefinitionDropdown.svelte @@ -0,0 +1,64 @@ + + +
+ + + [ + preset.id, + { + label: preset.name, + id: preset.id + } + ]) + ), + ...{ custom: { label: 'Custom value', id: '' } } + }} + on:change={({ detail }) => { + gui?.saveFieldValue(fieldDefinition.binding, { + isPreset: detail.value !== 'custom', + value: detail.value === 'custom' ? '' : detail.value || '' + }); + gui = gui; + }} + > + + {#if selectedRef === undefined} + Select a preset + {:else if selectedOption?.label} + {selectedOption.label} + {:else} + {selectedRef} + {/if} + + + +
+
{option.label ? option.label : ref}
+
+
+
+ + {#if gui?.isFieldPreset(fieldDefinition.binding) === false} + { + if (currentTarget instanceof HTMLInputElement) { + gui?.saveFieldValue(fieldDefinition.binding, { + isPreset: false, + value: currentTarget.value + }); + } + }} + /> + {/if} +
diff --git a/packages/ui-components/src/lib/index.ts b/packages/ui-components/src/lib/index.ts index 88874ce51..376f0ea7f 100644 --- a/packages/ui-components/src/lib/index.ts +++ b/packages/ui-components/src/lib/index.ts @@ -46,6 +46,10 @@ export { default as IconSuccess } from './components/IconSuccess.svelte'; export { default as IconTelegram } from './components/IconTelegram.svelte'; export { default as IconWalletConnect } from './components/IconWalletConnect.svelte'; export { default as IconWarning } from './components/IconWarning.svelte'; +export { default as FieldDefinitionDropdown } from './components/deployment/FieldDefinitionDropdown.svelte'; +export { default as DepositDropdown } from './components/deployment/DepositDropdown.svelte'; +export { default as FieldDefinitionButtons } from './components/deployment/FieldDefinitionButtons.svelte'; +export { default as DepositButtons } from './components/deployment/DepositButtons.svelte'; //Types export type { AppStoresInterface } from './types/appStores.ts'; diff --git a/packages/webapp/src/routes/deployment/+page.svelte b/packages/webapp/src/routes/deployment/+page.svelte index c7457a600..884e702c8 100644 --- a/packages/webapp/src/routes/deployment/+page.svelte +++ b/packages/webapp/src/routes/deployment/+page.svelte @@ -1,5 +1,10 @@ + +
+ { + gui = undefined; + }} + /> +
+ +
+ + + + {#if selectedRef === undefined} + Select a deployment + {:else if selectedOption?.label} + {selectedOption.label} + {:else} + {selectedRef} + {/if} + + + +
+
{option.label ? option.label : ref}
+
+
+
+
+ +{#if gui} + {#if isLimitStrat && selectTokens.size > 0} + + + {#each selectTokens.entries() as [token]} +
+ + + { + if (currentTarget instanceof HTMLInputElement) { + if (!gui) return; + await gui.saveSelectTokenAddress(token, currentTarget.value); + selectTokens = gui.getSelectTokens(); + gui = gui; + } + }} + /> +
+ {/each} + {/if} + + {#if allFieldDefinitions.length > 0} + + {#each allFieldDefinitions as fieldDefinition} + + {/each} + {/if} + + + + {#if selectedDeployment} +
+
+ +
+ + {#if useCustomVaultIds} + + + {#if gui?.getCurrentDeployment().deployment.order.inputs.length > 0} + + {#each gui?.getCurrentDeployment().deployment.order.inputs as input, i} +
+ + gui?.setVaultId(true, i, inputVaultIds[i])} + /> +
+ {/each} + {/if} + + {#if gui?.getCurrentDeployment().deployment.order.outputs.length > 0} + + {#each gui?.getCurrentDeployment().deployment.order.outputs as output, i} +
+ + gui?.setVaultId(false, i, outputVaultIds[i])} + /> +
+ {/each} + {/if} + {/if} +
+ + + {/if} +{/if} From 47168f4696e3157f66e6ebf9779474e53e328535 Mon Sep 17 00:00:00 2001 From: Jamie Harding Date: Fri, 20 Dec 2024 15:53:29 +0100 Subject: [PATCH 002/142] add more components --- .../deployment/DeploymentSteps.svelte | 108 +++++++++++++++ .../deployment/DepositButtons.svelte | 38 ++++-- .../deployment/FieldDefinitionButtons.svelte | 48 ++++--- .../components/deployment/SelectToken.svelte | 23 ++++ .../components/deployment/TokenInput.svelte | 23 ++++ .../components/deployment/TokenOutput.svelte | 23 ++++ packages/ui-components/src/lib/index.ts | 5 +- .../src/lib/types/deploymentSteps.ts | 82 ++++++++++++ .../webapp/src/routes/deployment/+page.svelte | 48 ++----- .../src/routes/deployment/new/+page.svelte | 126 +++++------------- 10 files changed, 357 insertions(+), 167 deletions(-) create mode 100644 packages/ui-components/src/lib/components/deployment/DeploymentSteps.svelte create mode 100644 packages/ui-components/src/lib/components/deployment/SelectToken.svelte create mode 100644 packages/ui-components/src/lib/components/deployment/TokenInput.svelte create mode 100644 packages/ui-components/src/lib/components/deployment/TokenOutput.svelte create mode 100644 packages/ui-components/src/lib/types/deploymentSteps.ts diff --git a/packages/ui-components/src/lib/components/deployment/DeploymentSteps.svelte b/packages/ui-components/src/lib/components/deployment/DeploymentSteps.svelte new file mode 100644 index 000000000..e2b1b4562 --- /dev/null +++ b/packages/ui-components/src/lib/components/deployment/DeploymentSteps.svelte @@ -0,0 +1,108 @@ + + +
+ +
+ Step {currentStep + 1} of {totalSteps} +
+ + + {#if steps[currentStep].type === 'tokens'} + + {:else if steps[currentStep].type === 'fields'} + + {:else if steps[currentStep].type === 'deposits'} + + {:else if steps[currentStep].type === 'tokenInput'} + + {:else if steps[currentStep].type === 'tokenOutput'} + + {/if} + + +
+ + + {#if currentStep === totalSteps - 1} + + {:else} + + {/if} +
+
diff --git a/packages/ui-components/src/lib/components/deployment/DepositButtons.svelte b/packages/ui-components/src/lib/components/deployment/DepositButtons.svelte index 6a0ad1d54..76c1e9424 100644 --- a/packages/ui-components/src/lib/components/deployment/DepositButtons.svelte +++ b/packages/ui-components/src/lib/components/deployment/DepositButtons.svelte @@ -25,39 +25,51 @@ } -
- +
+ +
+

+ {tokenInfos.get(deposit.token.address)?.name} +

+

Select deposit amount

+
-
+ +
{#each deposit.presets as preset} {/each}
+ {#if !gui?.isDepositPreset(deposit.token_name)} - { - if (currentTarget instanceof HTMLInputElement) { - gui?.saveDeposit(deposit.token_name, currentTarget.value); - } - }} - /> +
+ { + if (currentTarget instanceof HTMLInputElement) { + gui?.saveDeposit(deposit.token_name, currentTarget.value); + } + }} + /> +
{/if}
diff --git a/packages/ui-components/src/lib/components/deployment/FieldDefinitionButtons.svelte b/packages/ui-components/src/lib/components/deployment/FieldDefinitionButtons.svelte index b2025e7ba..e89c79ee6 100644 --- a/packages/ui-components/src/lib/components/deployment/FieldDefinitionButtons.svelte +++ b/packages/ui-components/src/lib/components/deployment/FieldDefinitionButtons.svelte @@ -5,7 +5,7 @@ export let fieldDefinition: GuiFieldDefinition; export let gui: DotrainOrderGui; - let showCustomInput: boolean = false; + let showCustomInput = false; function handlePresetClick(presetId: string) { gui?.saveFieldValue(fieldDefinition.binding, { @@ -24,22 +24,27 @@ }); gui = gui; } - - console.log(fieldDefinition); -
- +
+ +
+

{fieldDefinition.name}

+

+ {fieldDefinition.description} +

+
-
+ +
{#if fieldDefinition.presets} {#each fieldDefinition.presets as preset}
+ {#if !gui?.isFieldPreset(fieldDefinition.binding)} - { - if (currentTarget instanceof HTMLInputElement) { - gui?.saveFieldValue(fieldDefinition.binding, { - isPreset: false, - value: currentTarget.value - }); - } - }} - /> +
+ { + if (currentTarget instanceof HTMLInputElement) { + gui?.saveFieldValue(fieldDefinition.binding, { + isPreset: false, + value: currentTarget.value + }); + } + }} + /> +
{/if}
diff --git a/packages/ui-components/src/lib/components/deployment/SelectToken.svelte b/packages/ui-components/src/lib/components/deployment/SelectToken.svelte new file mode 100644 index 000000000..9020aa284 --- /dev/null +++ b/packages/ui-components/src/lib/components/deployment/SelectToken.svelte @@ -0,0 +1,23 @@ + + +
+ + { + if (currentTarget instanceof HTMLInputElement) { + if (!gui) return; + await gui.saveSelectTokenAddress(token, currentTarget.value); + selectTokens = gui.getSelectTokens(); + gui = gui; + } + }} + /> +
diff --git a/packages/ui-components/src/lib/components/deployment/TokenInput.svelte b/packages/ui-components/src/lib/components/deployment/TokenInput.svelte new file mode 100644 index 000000000..863e0291e --- /dev/null +++ b/packages/ui-components/src/lib/components/deployment/TokenInput.svelte @@ -0,0 +1,23 @@ + + +
+ + gui?.setVaultId(true, i, inputVaultIds[i])} + /> +
diff --git a/packages/ui-components/src/lib/components/deployment/TokenOutput.svelte b/packages/ui-components/src/lib/components/deployment/TokenOutput.svelte new file mode 100644 index 000000000..51e8ed228 --- /dev/null +++ b/packages/ui-components/src/lib/components/deployment/TokenOutput.svelte @@ -0,0 +1,23 @@ + + +
+ + gui?.setVaultId(false, i, outputVaultIds[i])} + /> +
diff --git a/packages/ui-components/src/lib/index.ts b/packages/ui-components/src/lib/index.ts index 376f0ea7f..1a7f9aaf8 100644 --- a/packages/ui-components/src/lib/index.ts +++ b/packages/ui-components/src/lib/index.ts @@ -50,7 +50,10 @@ export { default as FieldDefinitionDropdown } from './components/deployment/Fiel export { default as DepositDropdown } from './components/deployment/DepositDropdown.svelte'; export { default as FieldDefinitionButtons } from './components/deployment/FieldDefinitionButtons.svelte'; export { default as DepositButtons } from './components/deployment/DepositButtons.svelte'; - +export { default as DeploymentSteps } from './components/deployment/DeploymentSteps.svelte'; +export { default as TokenInput } from './components/deployment/TokenInput.svelte'; +export { default as TokenOutput } from './components/deployment/TokenOutput.svelte'; +export { default as SelectToken } from './components/deployment/SelectToken.svelte'; //Types export type { AppStoresInterface } from './types/appStores.ts'; export type { ConfigSource, OrderbookConfigSource, OrderbookRef } from './typeshare/config'; diff --git a/packages/ui-components/src/lib/types/deploymentSteps.ts b/packages/ui-components/src/lib/types/deploymentSteps.ts new file mode 100644 index 000000000..c1949c118 --- /dev/null +++ b/packages/ui-components/src/lib/types/deploymentSteps.ts @@ -0,0 +1,82 @@ +export type DeploymentStep = { + label: string; + type: 'tokens' | 'fields' | 'deposits' | 'vaults'; + fields: any[]; // Changed from 'items' to 'fields' +} + +// Example object: +const exampleDeploymentSteps = { + selectTokens: { + label: "Select Tokens", + type: "tokens", + fields: [ + { token: "USDC", address: "0x0000000000000000000000000000000000000000" }, + { token: "WETH", address: "0x0000000000000000000000000000000000000000" } + ] + }, + fieldDefinitions: { + label: "Field Values", + type: "fields", + fields: [ + { + name: "Price", + binding: "price", + presets: [ + { id: "preset1", name: "Market Price" }, + { id: "preset2", name: "Custom Price" } + ] + }, + { + name: "Amount", + binding: "amount", + presets: [ + { id: "small", name: "Small" }, + { id: "medium", name: "Medium" }, + { id: "large", name: "Large" } + ] + } + ] + }, + deposits: { + label: "Deposits", + type: "deposits", + fields: [ + { + token_name: "USDC", + token: { + address: "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", + name: "USD Coin", + symbol: "USDC", + decimals: 6 + }, + presets: ["100", "1000", "10000"] + } + ] + }, + vaults: { + label: "Vault IDs", + type: "vaults", + fields: [ + { + type: "input", + index: 0, + id: "1", + tokenInfo: { + name: "USD Coin", + symbol: "USDC", + decimals: 6 + } + }, + { + type: "output", + index: 0, + id: "2", + tokenInfo: { + name: "Wrapped Ether", + symbol: "WETH", + decimals: 18 + } + } + ] + } +}; \ No newline at end of file diff --git a/packages/webapp/src/routes/deployment/+page.svelte b/packages/webapp/src/routes/deployment/+page.svelte index 884e702c8..efbce270e 100644 --- a/packages/webapp/src/routes/deployment/+page.svelte +++ b/packages/webapp/src/routes/deployment/+page.svelte @@ -3,7 +3,10 @@ DropdownRadio, Checkbox, FieldDefinitionDropdown, - DepositDropdown + DepositDropdown, + TokenInput, + TokenOutput, + SelectToken } from '@rainlanguage/ui-components'; import { DotrainOrderGui, @@ -17,7 +20,7 @@ type TokenInfos, type Vault } from '@rainlanguage/orderbook/js_api'; - import { Button, Input, Label } from 'flowbite-svelte'; + import { Button, Label } from 'flowbite-svelte'; import { createWalletClient, custom, type Chain } from 'viem'; import { base, flare, arbitrum, polygon, bsc, mainnet, linea } from 'viem/chains'; @@ -231,21 +234,7 @@ {#each selectTokens.entries() as [token]} -
- - - { - if (currentTarget instanceof HTMLInputElement) { - if (!gui) return; - await gui.saveSelectTokenAddress(token, currentTarget.value); - selectTokens = gui.getSelectTokens(); - gui = gui; - } - }} - /> -
+ {/each} {/if} @@ -260,7 +249,6 @@ {#if allDeposits.length > 0} - {#each allDeposits as deposit} {/each} @@ -278,34 +266,14 @@ {#if allTokenInputs.length > 0} {#each allTokenInputs as input, i} -
- - gui?.setVaultId(true, i, inputVaultIds[i])} - /> -
+ {/each} {/if} {#if allTokenOutputs.length > 0} {#each allTokenOutputs as output, i} -
- - gui?.setVaultId(false, i, outputVaultIds[i])} - /> -
+ {/each} {/if} {/if} diff --git a/packages/webapp/src/routes/deployment/new/+page.svelte b/packages/webapp/src/routes/deployment/new/+page.svelte index b50f7b1d3..e38d2007d 100644 --- a/packages/webapp/src/routes/deployment/new/+page.svelte +++ b/packages/webapp/src/routes/deployment/new/+page.svelte @@ -1,10 +1,5 @@ -
+
-
+
Step {currentStep + 1} of {totalSteps}
@@ -94,7 +96,7 @@ {/if} -
+
{#if currentStep === totalSteps - 1} diff --git a/packages/ui-components/src/lib/components/deployment/DepositButtons.svelte b/packages/ui-components/src/lib/components/deployment/DepositButtons.svelte index 76c1e9424..20abcf631 100644 --- a/packages/ui-components/src/lib/components/deployment/DepositButtons.svelte +++ b/packages/ui-components/src/lib/components/deployment/DepositButtons.svelte @@ -25,39 +25,38 @@ } -
- +
-

+

{tokenInfos.get(deposit.token.address)?.name}

Select deposit amount

- -
- {#each deposit.presets as preset} + {#if deposit.presets} +
+ {#each deposit.presets as preset} + + {/each} - {/each} - -
+
+ {/if} - {#if !gui?.isDepositPreset(deposit.token_name)}
-
+
-

{fieldDefinition.name}

-

+

{fieldDefinition.name}

+

{fieldDefinition.description}

@@ -41,26 +41,29 @@ {#each fieldDefinition.presets as preset} {/each} + {/if} -
- {#if !gui?.isFieldPreset(fieldDefinition.binding)}
-
- { - gui = undefined; - }} - /> +
+
+ { + gui = undefined; + }} + /> +
+ +
+ + + + {#if selectedRef === undefined} + Select a deployment + {:else if selectedOption?.label} + {selectedOption.label} + {:else} + {selectedRef} + {/if} + + + +
+
{option.label ? option.label : ref}
+
+
+
+
+ +
+ {#if gui} + + {/if} +
- -
- - - - {#if selectedRef === undefined} - Select a deployment - {:else if selectedOption?.label} - {selectedOption.label} - {:else} - {selectedRef} - {/if} - - - -
-
{option.label ? option.label : ref}
-
-
-
-
- -{#if gui} - -{/if} From 9eae07364edd7dbec095af5436dba7030c1f6d64 Mon Sep 17 00:00:00 2001 From: Jamie Harding Date: Fri, 20 Dec 2024 16:53:56 +0100 Subject: [PATCH 004/142] move things around --- .../{ => wizard}/DeploymentSteps.svelte | 14 ++--- .../{ => wizard}/DepositButtons.svelte | 0 .../FieldDefinitionButtons.svelte | 57 ++++++++++--------- .../wizard/TokenInputButtons.svelte | 30 ++++++++++ .../TokenOutputButtons.svelte} | 0 packages/ui-components/src/lib/index.ts | 10 ++-- 6 files changed, 73 insertions(+), 38 deletions(-) rename packages/ui-components/src/lib/components/deployment/{ => wizard}/DeploymentSteps.svelte (89%) rename packages/ui-components/src/lib/components/deployment/{ => wizard}/DepositButtons.svelte (100%) rename packages/ui-components/src/lib/components/deployment/{ => wizard}/FieldDefinitionButtons.svelte (65%) create mode 100644 packages/ui-components/src/lib/components/deployment/wizard/TokenInputButtons.svelte rename packages/ui-components/src/lib/components/deployment/{TokenOutput.svelte => wizard/TokenOutputButtons.svelte} (100%) diff --git a/packages/ui-components/src/lib/components/deployment/DeploymentSteps.svelte b/packages/ui-components/src/lib/components/deployment/wizard/DeploymentSteps.svelte similarity index 89% rename from packages/ui-components/src/lib/components/deployment/DeploymentSteps.svelte rename to packages/ui-components/src/lib/components/deployment/wizard/DeploymentSteps.svelte index 26f3d4245..d95de848a 100644 --- a/packages/ui-components/src/lib/components/deployment/DeploymentSteps.svelte +++ b/packages/ui-components/src/lib/components/deployment/wizard/DeploymentSteps.svelte @@ -1,9 +1,10 @@ + +
+
+

+ Input {i + 1} ({tokenInfos.get(input.token.address)?.symbol}) +

+

Enter vault ID

+
+ +
+ gui?.setVaultId(true, i, inputVaultIds[i])} + /> +
+
diff --git a/packages/ui-components/src/lib/components/deployment/TokenOutput.svelte b/packages/ui-components/src/lib/components/deployment/wizard/TokenOutputButtons.svelte similarity index 100% rename from packages/ui-components/src/lib/components/deployment/TokenOutput.svelte rename to packages/ui-components/src/lib/components/deployment/wizard/TokenOutputButtons.svelte diff --git a/packages/ui-components/src/lib/index.ts b/packages/ui-components/src/lib/index.ts index 1a7f9aaf8..c196d8f0c 100644 --- a/packages/ui-components/src/lib/index.ts +++ b/packages/ui-components/src/lib/index.ts @@ -48,12 +48,14 @@ export { default as IconWalletConnect } from './components/IconWalletConnect.sve export { default as IconWarning } from './components/IconWarning.svelte'; export { default as FieldDefinitionDropdown } from './components/deployment/FieldDefinitionDropdown.svelte'; export { default as DepositDropdown } from './components/deployment/DepositDropdown.svelte'; -export { default as FieldDefinitionButtons } from './components/deployment/FieldDefinitionButtons.svelte'; -export { default as DepositButtons } from './components/deployment/DepositButtons.svelte'; -export { default as DeploymentSteps } from './components/deployment/DeploymentSteps.svelte'; +export { default as FieldDefinitionButtons } from './components/deployment/wizard/FieldDefinitionButtons.svelte'; +export { default as DepositButtons } from './components/deployment/wizard/DepositButtons.svelte'; +export { default as DeploymentSteps } from './components/deployment/wizard/DeploymentSteps.svelte'; export { default as TokenInput } from './components/deployment/TokenInput.svelte'; -export { default as TokenOutput } from './components/deployment/TokenOutput.svelte'; +export { default as TokenOutput } from './components/deployment/wizard/TokenOutputButtons.svelte'; export { default as SelectToken } from './components/deployment/SelectToken.svelte'; +export { default as TokenInputButtons } from './components/deployment/wizard/TokenInputButtons.svelte'; +export { default as TokenOutputButtons } from './components/deployment/wizard/TokenOutputButtons.svelte'; //Types export type { AppStoresInterface } from './types/appStores.ts'; export type { ConfigSource, OrderbookConfigSource, OrderbookRef } from './typeshare/config'; From ad7028f9cfa4db00099638116f016166751c76b6 Mon Sep 17 00:00:00 2001 From: Jamie Harding Date: Fri, 20 Dec 2024 18:04:59 +0100 Subject: [PATCH 005/142] why don't the types work? --- .../deployment/wizard/DeploymentSteps.svelte | 135 ++++++++++++++---- .../wizard/FieldDefinitionButtons.svelte | 6 +- .../wizard/TokenInputButtons.svelte | 3 +- .../wizard/TokenOutputButtons.svelte | 3 +- .../src/lib/types/wizardSteps.ts | 8 ++ .../webapp/src/routes/deployment/+page.svelte | 1 - 6 files changed, 120 insertions(+), 36 deletions(-) create mode 100644 packages/ui-components/src/lib/types/wizardSteps.ts diff --git a/packages/ui-components/src/lib/components/deployment/wizard/DeploymentSteps.svelte b/packages/ui-components/src/lib/components/deployment/wizard/DeploymentSteps.svelte index d95de848a..91d236d4d 100644 --- a/packages/ui-components/src/lib/components/deployment/wizard/DeploymentSteps.svelte +++ b/packages/ui-components/src/lib/components/deployment/wizard/DeploymentSteps.svelte @@ -4,6 +4,7 @@ import SelectToken from '../SelectToken.svelte'; import TokenInputButtons from './TokenInputButtons.svelte'; import TokenOutputButtons from './TokenOutputButtons.svelte'; + import type { WizardStep } from '../../../types/wizardSteps'; import type { DotrainOrderGui, @@ -36,38 +37,118 @@ export let handleAddOrder: () => Promise; export let tokenInfos: TokenInfos; - $: steps = [ + $: if (currentStep) { + const fieldValues = gui.getAllFieldValues(); + console.log(fieldValues); + } + + type TokenProps = { + token: string; + gui: DotrainOrderGui; + selectTokens: SelectTokens; + }; + + type FieldProps = { + fieldDefinition: GuiFieldDefinition; + gui: DotrainOrderGui; + }; + + type DepositProps = { + deposit: GuiDeposit; + gui: DotrainOrderGui; + tokenInfos: TokenInfos; + }; + + type TokenInputProps = { + i: number; + input: Vault; + tokenInfos: TokenInfos; + inputVaultIds: string[]; + gui: DotrainOrderGui; + }; + + type TokenOutputProps = { + i: number; + output: Vault; + tokenInfos: TokenInfos; + outputVaultIds: string[]; + gui: DotrainOrderGui; + }; + + type WizardStep = { + type: 'tokens' | 'fields' | 'deposits' | 'tokenInput' | 'tokenOutput'; + data: T; + }; + + let steps: ( + | WizardStep + | WizardStep + | WizardStep + | WizardStep + | WizardStep + )[] = [ ...(selectTokens.size > 0 && isLimitStrat - ? Array.from(selectTokens.entries()).map(([token]) => ({ - type: 'tokens' as const, - data: { token, gui, selectTokens } - })) + ? Array.from(selectTokens.entries()).map( + ([token]): WizardStep => ({ + type: 'tokens', + data: { token, gui, selectTokens } as { + token: string; + gui: DotrainOrderGui; + selectTokens: SelectTokens; + } + }) + ) : []), - ...allFieldDefinitions.map((fieldDefinition) => ({ - type: 'fields' as const, - data: { fieldDefinition, gui } - })), - - ...allDeposits.map((deposit) => ({ - type: 'deposits' as const, - data: { deposit, gui, tokenInfos } - })), - - ...allTokenInputs.map((input, i) => ({ - type: 'tokenInput' as const, - data: { input, gui, tokenInfos, i, inputVaultIds } - })), - ...allTokenOutputs.map((output, i) => ({ - type: 'tokenOutput' as const, - data: { output, gui, tokenInfos, i, outputVaultIds } - })) + ...allFieldDefinitions.map( + (fieldDefinition): WizardStep => ({ + type: 'fields', + data: { fieldDefinition, gui } as { + fieldDefinition: GuiFieldDefinition; + gui: DotrainOrderGui; + } + }) + ), + + ...allDeposits.map( + (deposit): WizardStep => ({ + type: 'deposits', + data: { deposit, gui, tokenInfos } as { + deposit: GuiDeposit; + gui: DotrainOrderGui; + tokenInfos: TokenInfos; + } + }) + ), + + ...allTokenInputs.map( + (input, i): WizardStep => ({ + type: 'tokenInput', + data: { input, gui, tokenInfos, i, inputVaultIds } as { + input: Vault; + gui: DotrainOrderGui; + tokenInfos: TokenInfos; + i: number; + inputVaultIds: string[]; + } + }) + ), + ...allTokenOutputs.map( + (output, i): WizardStep => ({ + type: 'tokenOutput', + data: { output, gui, tokenInfos, i, outputVaultIds } as { + output: Vault; + gui: DotrainOrderGui; + tokenInfos: TokenInfos; + i: number; + outputVaultIds: string[]; + } + }) + ) ]; let currentStep = 0; - $: console.log(steps); - const nextStep = () => { if (currentStep < totalSteps - 1) currentStep++; }; @@ -78,12 +159,10 @@
- -
+
Step {currentStep + 1} of {totalSteps}
- {#if steps[currentStep].type === 'tokens'} {:else if steps[currentStep].type === 'fields'} diff --git a/packages/ui-components/src/lib/components/deployment/wizard/FieldDefinitionButtons.svelte b/packages/ui-components/src/lib/components/deployment/wizard/FieldDefinitionButtons.svelte index e18ea0c13..23bb557dc 100644 --- a/packages/ui-components/src/lib/components/deployment/wizard/FieldDefinitionButtons.svelte +++ b/packages/ui-components/src/lib/components/deployment/wizard/FieldDefinitionButtons.svelte @@ -1,5 +1,5 @@
- Step {currentStep + 1} of {steps.length} + Step {deploymentSteps.indexOf(currentStep) + 1} of {deploymentSteps.length}
- {#if steps[currentStep].type === 'tokens'} - - {:else if steps[currentStep].type === 'fields'} - - {:else if steps[currentStep].type === 'deposits'} - - {:else if steps[currentStep].type === 'tokenInput'} - - {:else if steps[currentStep].type === 'tokenOutput'} - + {#if currentStep.type === 'tokens'} + + {:else if currentStep.type === 'fields'} + + {:else if currentStep.type === 'deposits'} + + {:else if currentStep.type === 'tokenInput'} + + {:else if currentStep.type === 'tokenOutput'} + {/if} +
- + + {#if deploymentSteps.indexOf(currentStep) > 0} + + {/if} - {#if currentStep === steps.length - 1} + {#if deploymentSteps.indexOf(currentStep) === deploymentSteps.length - 1} {:else} - {/if} diff --git a/packages/ui-components/src/lib/components/deployment/wizard/DepositButtons.svelte b/packages/ui-components/src/lib/components/deployment/wizard/DepositButtons.svelte index c1a6588cd..1280ba8ef 100644 --- a/packages/ui-components/src/lib/components/deployment/wizard/DepositButtons.svelte +++ b/packages/ui-components/src/lib/components/deployment/wizard/DepositButtons.svelte @@ -4,15 +4,20 @@ type GuiDeposit, type TokenInfos } from '@rainlanguage/orderbook/js_api'; - import { Label, Input, Button } from 'flowbite-svelte'; + import { Input, Button } from 'flowbite-svelte'; + import type { StepType } from '../../../types/wizardSteps'; export let deposit: GuiDeposit; export let gui: DotrainOrderGui; export let tokenInfos: TokenInfos; + export let type: StepType; let showCustomInput = false; + $: console.log('deposit', deposit); + function handlePresetClick(preset: string) { + console.log('PRESET CLICK'); gui?.saveDeposit(deposit.token_name, preset); showCustomInput = false; gui = gui; @@ -38,10 +43,7 @@ {#each deposit.presets as preset} {#if deploymentSteps.indexOf(currentStep) > 0} {/if} diff --git a/packages/ui-components/src/lib/components/deployment/wizard/FieldDefinitionButtons.svelte b/packages/ui-components/src/lib/components/deployment/wizard/FieldDefinitionButtons.svelte index b4f81df15..078101eef 100644 --- a/packages/ui-components/src/lib/components/deployment/wizard/FieldDefinitionButtons.svelte +++ b/packages/ui-components/src/lib/components/deployment/wizard/FieldDefinitionButtons.svelte @@ -1,12 +1,21 @@
- Step {deploymentSteps.indexOf(currentStep) + 1} of {deploymentSteps.length} + Step {currentStep + 1} of {deploymentSteps.length}
- {#if currentStep.type === 'tokens'} - - {:else if currentStep.type === 'fields'} - - {:else if currentStep.type === 'deposits'} - - {:else if currentStep.type === 'tokenInput'} - - {:else if currentStep.type === 'tokenOutput'} - + {#if deploymentSteps[currentStep].type === 'tokens'} + + {:else if deploymentSteps[currentStep].type === 'fields'} + + {:else if deploymentSteps[currentStep].type === 'deposits'} + + {:else if deploymentSteps[currentStep].type === 'tokenInput'} + + {:else if deploymentSteps[currentStep].type === 'tokenOutput'} + {/if}
- {#if deploymentSteps.indexOf(currentStep) > 0} + {#if currentStep > 0} {/if} - {#if deploymentSteps.indexOf(currentStep) === deploymentSteps.length - 1} + {#if currentStep === deploymentSteps.length - 1} {:else} diff --git a/packages/ui-components/src/lib/components/deployment/wizard/FieldDefinitionButtons.svelte b/packages/ui-components/src/lib/components/deployment/wizard/FieldDefinitionButtons.svelte index 078101eef..422c690e5 100644 --- a/packages/ui-components/src/lib/components/deployment/wizard/FieldDefinitionButtons.svelte +++ b/packages/ui-components/src/lib/components/deployment/wizard/FieldDefinitionButtons.svelte @@ -1,21 +1,12 @@
diff --git a/packages/ui-components/src/lib/components/deployment/wizard/TokenOutputButtons.svelte b/packages/ui-components/src/lib/components/deployment/wizard/TokenOutputButtons.svelte index e2023e2b7..696251fee 100644 --- a/packages/ui-components/src/lib/components/deployment/wizard/TokenOutputButtons.svelte +++ b/packages/ui-components/src/lib/components/deployment/wizard/TokenOutputButtons.svelte @@ -9,6 +9,7 @@ export let outputVaultIds: string[]; export let gui: DotrainOrderGui; export let type: StepType; + export let useCustomVaultIds: boolean;
From a9efcb8c8ca5b50fb0f94de7ef6c05bca0e256d8 Mon Sep 17 00:00:00 2001 From: Jamie Harding Date: Mon, 23 Dec 2024 13:56:50 +0100 Subject: [PATCH 011/142] add --- .../__tests__/FieldDefinitionButtons.test.ts | 127 ++++++++++++++++++ 1 file changed, 127 insertions(+) create mode 100644 packages/ui-components/src/__tests__/FieldDefinitionButtons.test.ts diff --git a/packages/ui-components/src/__tests__/FieldDefinitionButtons.test.ts b/packages/ui-components/src/__tests__/FieldDefinitionButtons.test.ts new file mode 100644 index 000000000..f8eb82e1c --- /dev/null +++ b/packages/ui-components/src/__tests__/FieldDefinitionButtons.test.ts @@ -0,0 +1,127 @@ +import { render, fireEvent } from '@testing-library/svelte'; +import { describe, it, expect, vi, beforeEach } from 'vitest'; +import FieldDefinitionButtons from '../lib/components/deployment/wizard/FieldDefinitionButtons.svelte'; +import { DotrainOrderGui } from '@rainlanguage/orderbook/js_api'; +import deploymentStepsStore from '../lib/components/deployment/wizard/deploymentStepsStore'; + +// Mock the DotrainOrderGui class +vi.mock('@rainlanguage/orderbook/js_api', () => ({ + DotrainOrderGui: vi.fn().mockImplementation(() => ({ + saveFieldValue: vi.fn(), + getFieldValue: vi.fn(), + isFieldPreset: vi.fn() + })) +})); + +describe('FieldDefinitionButtons', () => { + let mockGui: DotrainOrderGui; + const mockFieldDefinition = { + binding: 'test-binding', + name: 'Test Field', + description: 'Test Description', + presets: [ + { id: 'preset1', name: 'Preset 1', value: 'value1' }, + { id: 'preset2', name: 'Preset 2', value: 'value2' } + ] + }; + + beforeEach(() => { + mockGui = new DotrainOrderGui(); + vi.spyOn(deploymentStepsStore, 'updateDeploymentStep'); + }); + + it('renders field name and description', () => { + const { getByText } = render(FieldDefinitionButtons, { + props: { + fieldDefinition: mockFieldDefinition, + gui: mockGui, + currentStep: 0 + } + }); + + expect(getByText('Test Field')).toBeTruthy(); + expect(getByText('Test Description')).toBeTruthy(); + }); + + it('renders preset buttons', () => { + const { getByText } = render(FieldDefinitionButtons, { + props: { + fieldDefinition: mockFieldDefinition, + gui: mockGui, + currentStep: 0 + } + }); + + expect(getByText('Preset 1')).toBeTruthy(); + expect(getByText('Preset 2')).toBeTruthy(); + expect(getByText('Custom')).toBeTruthy(); + }); + + it('handles preset button clicks', async () => { + const { getByText } = render(FieldDefinitionButtons, { + props: { + fieldDefinition: mockFieldDefinition, + gui: mockGui, + currentStep: 0 + } + }); + + await fireEvent.click(getByText('Preset 1')); + + expect(mockGui.saveFieldValue).toHaveBeenCalledWith('test-binding', { + isPreset: true, + value: 'preset1' + }); + expect(deploymentStepsStore.updateDeploymentStep).toHaveBeenCalled(); + }); + + it('shows custom input when Custom button is clicked', async () => { + const { getByText, getByPlaceholderText } = render(FieldDefinitionButtons, { + props: { + fieldDefinition: mockFieldDefinition, + gui: mockGui, + currentStep: 0 + } + }); + + await fireEvent.click(getByText('Custom')); + expect(getByPlaceholderText('Enter custom value')).toBeTruthy(); + }); + + it('handles custom input changes', async () => { + const { getByText, getByPlaceholderText } = render(FieldDefinitionButtons, { + props: { + fieldDefinition: mockFieldDefinition, + gui: mockGui, + currentStep: 0 + } + }); + + await fireEvent.click(getByText('Custom')); + const input = getByPlaceholderText('Enter custom value'); + await fireEvent.input(input, { target: { value: 'custom value' } }); + + expect(mockGui.saveFieldValue).toHaveBeenCalledWith('test-binding', { + isPreset: false, + value: 'custom value' + }); + expect(deploymentStepsStore.updateDeploymentStep).toHaveBeenCalled(); + }); + + it('does not show Custom button for is-fast-exit binding', () => { + const fastExitFieldDef = { + ...mockFieldDefinition, + binding: 'is-fast-exit' + }; + + const { queryByText } = render(FieldDefinitionButtons, { + props: { + fieldDefinition: fastExitFieldDef, + gui: mockGui, + currentStep: 0 + } + }); + + expect(queryByText('Custom')).toBeNull(); + }); +}); From 682007cb92a7722122e35cdd5ad68973581ac281 Mon Sep 17 00:00:00 2001 From: Jamie Harding Date: Mon, 23 Dec 2024 14:04:30 +0100 Subject: [PATCH 012/142] update log --- .../deployment/wizard/DepositButtons.svelte | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/packages/ui-components/src/lib/components/deployment/wizard/DepositButtons.svelte b/packages/ui-components/src/lib/components/deployment/wizard/DepositButtons.svelte index 1280ba8ef..59f9b6858 100644 --- a/packages/ui-components/src/lib/components/deployment/wizard/DepositButtons.svelte +++ b/packages/ui-components/src/lib/components/deployment/wizard/DepositButtons.svelte @@ -19,6 +19,7 @@ function handlePresetClick(preset: string) { console.log('PRESET CLICK'); gui?.saveDeposit(deposit.token_name, preset); + console.log(gui?.getDeposits()); showCustomInput = false; gui = gui; } @@ -30,12 +31,12 @@ } -
+

{tokenInfos.get(deposit.token.address)?.name}

-

Select deposit amount

+

Select deposit amount

{#if deposit.presets} @@ -43,7 +44,10 @@ {#each deposit.presets as preset}
diff --git a/packages/ui-components/src/lib/components/deployment/wizard/DeploymentSteps.svelte b/packages/ui-components/src/lib/components/deployment/wizard/DeploymentSteps.svelte index 6d24e8a5f..c03ea68c6 100644 --- a/packages/ui-components/src/lib/components/deployment/wizard/DeploymentSteps.svelte +++ b/packages/ui-components/src/lib/components/deployment/wizard/DeploymentSteps.svelte @@ -45,8 +45,6 @@ deploymentStepsStore.populateDeploymentSteps(deploymentSteps); - $: console.log($deploymentStepsStore); - $: currentStep = 0; const nextStep = () => { diff --git a/packages/ui-components/src/lib/components/deployment/wizard/DepositButtons.svelte b/packages/ui-components/src/lib/components/deployment/wizard/DepositButtons.svelte index 59f9b6858..239c115d2 100644 --- a/packages/ui-components/src/lib/components/deployment/wizard/DepositButtons.svelte +++ b/packages/ui-components/src/lib/components/deployment/wizard/DepositButtons.svelte @@ -5,21 +5,15 @@ type TokenInfos } from '@rainlanguage/orderbook/js_api'; import { Input, Button } from 'flowbite-svelte'; - import type { StepType } from '../../../types/wizardSteps'; export let deposit: GuiDeposit; export let gui: DotrainOrderGui; export let tokenInfos: TokenInfos; - export let type: StepType; - let showCustomInput = false; - - $: console.log('deposit', deposit); + let showCustomInput = !gui?.isDepositPreset(deposit.token_name); function handlePresetClick(preset: string) { - console.log('PRESET CLICK'); gui?.saveDeposit(deposit.token_name, preset); - console.log(gui?.getDeposits()); showCustomInput = false; gui = gui; } @@ -65,7 +59,7 @@
{/if} - {#if !gui?.isDepositPreset(deposit.token_name)} + {#if showCustomInput}
Date: Fri, 27 Dec 2024 15:07:27 +0100 Subject: [PATCH 014/142] test getDeploymentSteps --- .../src/__tests__/getDeploymentSteps.test.ts | 98 +++++++++++++++++++ 1 file changed, 98 insertions(+) create mode 100644 packages/ui-components/src/__tests__/getDeploymentSteps.test.ts diff --git a/packages/ui-components/src/__tests__/getDeploymentSteps.test.ts b/packages/ui-components/src/__tests__/getDeploymentSteps.test.ts new file mode 100644 index 000000000..c1b7fc9b0 --- /dev/null +++ b/packages/ui-components/src/__tests__/getDeploymentSteps.test.ts @@ -0,0 +1,98 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import { getDeploymentSteps } from '../lib/components/deployment/wizard/getDeploymentSteps'; +import { describe, it, expect } from 'vitest'; + +describe('getDeploymentSteps', () => { + const mockGui = {} as any; + const mockTokenInfos = {} as any; + + it('should return empty array when no inputs provided', () => { + const steps = getDeploymentSteps( + new Map(), + false, + [], + mockGui, + [], + [], + [], + [], + [], + mockTokenInfos + ); + + expect(steps).toEqual([]); + }); + + it('should include select token steps for limit strategy', () => { + const selectTokens = new Map([['TOKEN1', 'address1']]); + + const steps = getDeploymentSteps( + selectTokens, + true, + [], + mockGui, + [], + [], + [], + [], + [], + mockTokenInfos + ); + + expect(steps[0]).toEqual({ + type: 'tokens', + token: 'TOKEN1', + gui: mockGui, + selectTokens + }); + }); + + it('should not include select token steps when not limit strategy', () => { + const selectTokens = new Map([['TOKEN1', 'address1']]); + + const steps = getDeploymentSteps( + selectTokens, + false, + [], + mockGui, + [], + [], + [], + [], + [], + mockTokenInfos + ); + + expect(steps).toEqual([]); + }); + + it('should include all step types in correct order', () => { + const selectTokens = new Map([['TOKEN1', 'address1']]); + const fieldDefinitions = [{ id: 'field1' }] as any; + const deposits = [{ id: 'deposit1' }] as any; + const inputs = [{ id: 'input1' }] as any; + const outputs = [{ id: 'output1' }] as any; + const inputVaultIds = ['vault1']; + const outputVaultIds = ['vault2']; + + const steps = getDeploymentSteps( + selectTokens, + true, + fieldDefinitions, + mockGui, + deposits, + inputs, + outputs, + inputVaultIds, + outputVaultIds, + mockTokenInfos + ); + + expect(steps).toHaveLength(5); + expect(steps[0].type).toBe('tokens'); + expect(steps[1].type).toBe('fields'); + expect(steps[2].type).toBe('deposits'); + expect(steps[3].type).toBe('tokenInput'); + expect(steps[4].type).toBe('tokenOutput'); + }); +}); \ No newline at end of file From c8d56d2d18f78a9918546441d36815ad7e582ac0 Mon Sep 17 00:00:00 2001 From: Jamie Harding Date: Fri, 27 Dec 2024 15:09:37 +0100 Subject: [PATCH 015/142] test the deploymentStepsStore --- .../__tests__/deploymentStepsStore.test.ts | 106 ++++++++++++++++++ 1 file changed, 106 insertions(+) create mode 100644 packages/ui-components/src/__tests__/deploymentStepsStore.test.ts diff --git a/packages/ui-components/src/__tests__/deploymentStepsStore.test.ts b/packages/ui-components/src/__tests__/deploymentStepsStore.test.ts new file mode 100644 index 000000000..e51cd8828 --- /dev/null +++ b/packages/ui-components/src/__tests__/deploymentStepsStore.test.ts @@ -0,0 +1,106 @@ +import { get } from 'svelte/store'; +import deploymentStepsStore from '../lib/components/deployment/wizard/deploymentStepsStore' +import type { WizardStep, TokenInputStep, FieldStep } from '../lib/types/wizardSteps'; + +describe('deploymentStepsStore', () => { + beforeEach(() => { + deploymentStepsStore.reset(); + }); + + it('should initialize with empty array', () => { + const steps = get(deploymentStepsStore); + expect(steps).toEqual([]); + }); + + it('should populate steps correctly', () => { + const mockSteps: WizardStep[] = [ + { + type: 'tokenInput', + input: { + token: '0x123...', + decimals: 18, + symbol: 'TEST' + }, + gui: { + name: 'Test GUI', + description: 'Test Description', + }, + tokenInfos: { + }, + i: 0, + inputVaultIds: ['vault1', 'vault2'] + } as unknown as TokenInputStep, + { + type: 'fields', + fieldDefinition: { + name: 'Test Field', + type: 'uint256', + }, + gui: { + name: 'Test GUI', + description: 'Test Description', + } + } as unknown as FieldStep + ]; + + deploymentStepsStore.populateDeploymentSteps(mockSteps); + const steps = get(deploymentStepsStore); + + expect(steps).toEqual(mockSteps); + }); + + it('should update a specific step correctly', () => { + const initialSteps: WizardStep[] = [ + { + type: 'tokenInput', + input: { + token: '0x123...', + decimals: 18, + symbol: 'TEST' + }, + gui: { + name: 'Test GUI', + description: 'Test Description' + }, + tokenInfos: { + }, + i: 0, + inputVaultIds: ['vault1'] + } as unknown as TokenInputStep + ]; + + deploymentStepsStore.populateDeploymentSteps(initialSteps); + + const updatedStep: TokenInputStep = { + ...initialSteps[0], + inputVaultIds: ['vault1', 'vault2'] + } as unknown as TokenInputStep; + + deploymentStepsStore.updateDeploymentStep(0, updatedStep); + + const steps = get(deploymentStepsStore); + expect(steps[0]).toEqual(updatedStep); + }); + + it('should reset store to initial state', () => { + const mockSteps: WizardStep[] = [ + { + type: 'fields', + fieldDefinition: { + name: 'Test Field', + type: 'uint256', + }, + gui: { + name: 'Test GUI', + description: 'Test Description', + } + } as unknown as FieldStep + ]; + + deploymentStepsStore.populateDeploymentSteps(mockSteps); + deploymentStepsStore.reset(); + + const steps = get(deploymentStepsStore); + expect(steps).toEqual([]); + }); +}); \ No newline at end of file From 59b1f60a082efe71bd8dc72bca82448abef80332 Mon Sep 17 00:00:00 2001 From: Jamie Harding Date: Fri, 27 Dec 2024 15:09:49 +0100 Subject: [PATCH 016/142] change type --- .../components/deployment/wizard/getDeploymentSteps.ts | 4 ++-- packages/ui-components/src/lib/types/wizardSteps.ts | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/ui-components/src/lib/components/deployment/wizard/getDeploymentSteps.ts b/packages/ui-components/src/lib/components/deployment/wizard/getDeploymentSteps.ts index ee64cfb25..5f55f31f4 100644 --- a/packages/ui-components/src/lib/components/deployment/wizard/getDeploymentSteps.ts +++ b/packages/ui-components/src/lib/components/deployment/wizard/getDeploymentSteps.ts @@ -4,7 +4,7 @@ import type { DepositStep, FieldStep, TokenInputStep } from "$lib/types/wizardSt import type { SelectTokenStep } from "$lib/types/wizardSteps"; -import type { DotrainOrderGui, GuiFieldDefinition, TokenInfos, Vault , GuiDeposit} from '@rainlanguage/orderbook/js_api'; +import type { DotrainOrderGui, GuiFieldDefinition, TokenInfos, Vault, TokenDeposit} from '@rainlanguage/orderbook/js_api'; import type { WizardStep } from '../../../types/wizardSteps'; export const getDeploymentSteps = ( @@ -12,7 +12,7 @@ export const getDeploymentSteps = ( isLimitStrat: boolean, allFieldDefinitions: GuiFieldDefinition[], gui: DotrainOrderGui, - allDeposits: GuiDeposit[], + allDeposits: TokenDeposit[], allTokenInputs: Vault[], allTokenOutputs: Vault[], inputVaultIds: string[], diff --git a/packages/ui-components/src/lib/types/wizardSteps.ts b/packages/ui-components/src/lib/types/wizardSteps.ts index 5162f33ef..0729e498e 100644 --- a/packages/ui-components/src/lib/types/wizardSteps.ts +++ b/packages/ui-components/src/lib/types/wizardSteps.ts @@ -2,9 +2,9 @@ import type { DotrainOrderGui, SelectTokens, GuiFieldDefinition, - GuiDeposit, TokenInfos, - Vault + Vault, + TokenDeposit } from '@rainlanguage/orderbook/js_api'; export type StepType = 'tokens' | 'fields' | 'deposits' | 'tokenInput' | 'tokenOutput'; @@ -28,7 +28,7 @@ export interface FieldStep extends BaseWizardStep { export interface DepositStep extends BaseWizardStep { type: 'deposits'; - deposit: GuiDeposit; + deposit: TokenDeposit; gui: DotrainOrderGui; tokenInfos: TokenInfos; } @@ -51,4 +51,4 @@ export interface TokenOutputStep extends BaseWizardStep { outputVaultIds: string[]; } -export type WizardStep = TokenStep | FieldStep | DepositStep | TokenInputStep | TokenOutputStep; +export type WizardStep = SelectTokenStep | FieldStep | DepositStep | TokenInputStep | TokenOutputStep; From 8ed4d0f7c9d2dd122fca23b37ebd790995915c27 Mon Sep 17 00:00:00 2001 From: Jamie Harding Date: Fri, 27 Dec 2024 15:19:50 +0100 Subject: [PATCH 017/142] add field def props --- .../__tests__/FIeldDefinitionDropdown.test.ts | 89 +++++++++++++++++++ 1 file changed, 89 insertions(+) create mode 100644 packages/ui-components/src/__tests__/FIeldDefinitionDropdown.test.ts diff --git a/packages/ui-components/src/__tests__/FIeldDefinitionDropdown.test.ts b/packages/ui-components/src/__tests__/FIeldDefinitionDropdown.test.ts new file mode 100644 index 000000000..c68ace2a4 --- /dev/null +++ b/packages/ui-components/src/__tests__/FIeldDefinitionDropdown.test.ts @@ -0,0 +1,89 @@ +import { describe, it, expect, vi, beforeEach, type Mock } from 'vitest'; +import { render, fireEvent, screen } from '@testing-library/svelte'; +import FieldDefinitionDropdown from '../lib/components/deployment/FieldDefinitionDropdown.svelte'; +import type { DotrainOrderGui, GuiFieldDefinition } from '@rainlanguage/orderbook/js_api'; +import type { ComponentProps } from 'svelte'; + + +export type FieldDefinitionDropdownProps = ComponentProps; + +describe('FieldDefinitionDropdown', () => { + let mockGui: DotrainOrderGui; + let fieldDefinition: GuiFieldDefinition; + + beforeEach(() => { + mockGui = { + saveFieldValue: vi.fn(), + isFieldPreset: vi.fn(), + } as unknown as DotrainOrderGui; + + fieldDefinition = { + name: 'Test Field', + binding: 'test-binding', + presets: [ + { id: 'preset1', name: 'Preset 1', value:'' }, + { id: 'preset2', name: 'Preset 2', value:''} + ] + } as unknown as GuiFieldDefinition + }); + + it('renders field name correctly', () => { + render(FieldDefinitionDropdown, { props: { fieldDefinition, gui: mockGui } }); + expect(screen.getByText('Test Field')).toBeInTheDocument(); + }); + + it('shows presets in dropdown', async () => { + render(FieldDefinitionDropdown, { props: { fieldDefinition, gui: mockGui } }); + + // Open dropdown + const dropdown = screen.getByText('Select a preset'); + await fireEvent.click(dropdown); + + // Check if presets are rendered + expect(screen.getByText('Preset 1')).toBeInTheDocument(); + expect(screen.getByText('Preset 2')).toBeInTheDocument(); + expect(screen.getByText('Custom value')).toBeInTheDocument(); + }); + + it('calls saveFieldValue when preset is selected', async () => { + render(FieldDefinitionDropdown, { props: { fieldDefinition, gui: mockGui } }); + + // Open dropdown and select preset + const dropdown = screen.getByText('Select a preset'); + await fireEvent.click(dropdown); + await fireEvent.click(screen.getByText('Preset 1')); + + expect(mockGui.saveFieldValue).toHaveBeenCalledWith('test-binding', { + isPreset: true, + value: 'preset1' + }); + }); + + it('shows input field when custom value is selected', async () => { + (mockGui.isFieldPreset as Mock).mockReturnValue(false); + + render(FieldDefinitionDropdown, { props: { fieldDefinition, gui: mockGui } }); + + // Open dropdown and select custom + const dropdown = screen.getByText('Select a preset'); + await fireEvent.click(dropdown); + await fireEvent.click(screen.getByText('Custom value')); + + // Check if input field appears + const input = screen.getByPlaceholderText('Enter value'); + expect(input).toBeInTheDocument(); + + // Test input change + await fireEvent.change(input, { target: { value: 'custom input' } }); + expect(mockGui.saveFieldValue).toHaveBeenCalledWith('test-binding', { + isPreset: false, + value: 'custom input' + }); + }); + + it('handles case when gui is not provided', () => { + render(FieldDefinitionDropdown, { props: { fieldDefinition } as FieldDefinitionDropdownProps }); + expect(screen.getByText('Test Field')).toBeInTheDocument(); + // Should not throw any errors + }); +}); \ No newline at end of file From ab58f583ac472d18d37ea5d6c4da05ad95ca9bd9 Mon Sep 17 00:00:00 2001 From: Jamie Harding Date: Fri, 27 Dec 2024 15:36:17 +0100 Subject: [PATCH 018/142] more tests and types --- .../__tests__/FIeldDefinitionDropdown.test.ts | 159 ++++++------ .../__tests__/FieldDefinitionButtons.test.ts | 230 +++++++++--------- .../src/__tests__/SelectToken.test.ts | 56 +++++ .../src/__tests__/TokenInput.test.ts | 79 ++++++ .../__tests__/deploymentStepsStore.test.ts | 178 +++++++------- .../src/__tests__/getDeploymentSteps.test.ts | 164 ++++++------- .../components/deployment/TokenInput.svelte | 2 +- .../wizard/TokenInputButtons.svelte | 1 - .../deployment/wizard/deploymentStepsStore.ts | 20 +- .../deployment/wizard/getDeploymentSteps.ts | 21 +- .../src/lib/types/wizardSteps.ts | 7 +- 11 files changed, 529 insertions(+), 388 deletions(-) create mode 100644 packages/ui-components/src/__tests__/SelectToken.test.ts create mode 100644 packages/ui-components/src/__tests__/TokenInput.test.ts diff --git a/packages/ui-components/src/__tests__/FIeldDefinitionDropdown.test.ts b/packages/ui-components/src/__tests__/FIeldDefinitionDropdown.test.ts index c68ace2a4..099c9020b 100644 --- a/packages/ui-components/src/__tests__/FIeldDefinitionDropdown.test.ts +++ b/packages/ui-components/src/__tests__/FIeldDefinitionDropdown.test.ts @@ -4,86 +4,85 @@ import FieldDefinitionDropdown from '../lib/components/deployment/FieldDefinitio import type { DotrainOrderGui, GuiFieldDefinition } from '@rainlanguage/orderbook/js_api'; import type { ComponentProps } from 'svelte'; - export type FieldDefinitionDropdownProps = ComponentProps; describe('FieldDefinitionDropdown', () => { - let mockGui: DotrainOrderGui; - let fieldDefinition: GuiFieldDefinition; - - beforeEach(() => { - mockGui = { - saveFieldValue: vi.fn(), - isFieldPreset: vi.fn(), - } as unknown as DotrainOrderGui; - - fieldDefinition = { - name: 'Test Field', - binding: 'test-binding', - presets: [ - { id: 'preset1', name: 'Preset 1', value:'' }, - { id: 'preset2', name: 'Preset 2', value:''} - ] - } as unknown as GuiFieldDefinition - }); - - it('renders field name correctly', () => { - render(FieldDefinitionDropdown, { props: { fieldDefinition, gui: mockGui } }); - expect(screen.getByText('Test Field')).toBeInTheDocument(); - }); - - it('shows presets in dropdown', async () => { - render(FieldDefinitionDropdown, { props: { fieldDefinition, gui: mockGui } }); - - // Open dropdown - const dropdown = screen.getByText('Select a preset'); - await fireEvent.click(dropdown); - - // Check if presets are rendered - expect(screen.getByText('Preset 1')).toBeInTheDocument(); - expect(screen.getByText('Preset 2')).toBeInTheDocument(); - expect(screen.getByText('Custom value')).toBeInTheDocument(); - }); - - it('calls saveFieldValue when preset is selected', async () => { - render(FieldDefinitionDropdown, { props: { fieldDefinition, gui: mockGui } }); - - // Open dropdown and select preset - const dropdown = screen.getByText('Select a preset'); - await fireEvent.click(dropdown); - await fireEvent.click(screen.getByText('Preset 1')); - - expect(mockGui.saveFieldValue).toHaveBeenCalledWith('test-binding', { - isPreset: true, - value: 'preset1' - }); - }); - - it('shows input field when custom value is selected', async () => { - (mockGui.isFieldPreset as Mock).mockReturnValue(false); - - render(FieldDefinitionDropdown, { props: { fieldDefinition, gui: mockGui } }); - - // Open dropdown and select custom - const dropdown = screen.getByText('Select a preset'); - await fireEvent.click(dropdown); - await fireEvent.click(screen.getByText('Custom value')); - - // Check if input field appears - const input = screen.getByPlaceholderText('Enter value'); - expect(input).toBeInTheDocument(); - - // Test input change - await fireEvent.change(input, { target: { value: 'custom input' } }); - expect(mockGui.saveFieldValue).toHaveBeenCalledWith('test-binding', { - isPreset: false, - value: 'custom input' - }); - }); - - it('handles case when gui is not provided', () => { - render(FieldDefinitionDropdown, { props: { fieldDefinition } as FieldDefinitionDropdownProps }); - expect(screen.getByText('Test Field')).toBeInTheDocument(); - // Should not throw any errors - }); -}); \ No newline at end of file + let mockGui: DotrainOrderGui; + let fieldDefinition: GuiFieldDefinition; + + beforeEach(() => { + mockGui = { + saveFieldValue: vi.fn(), + isFieldPreset: vi.fn() + } as unknown as DotrainOrderGui; + + fieldDefinition = { + name: 'Test Field', + binding: 'test-binding', + presets: [ + { id: 'preset1', name: 'Preset 1', value: '' }, + { id: 'preset2', name: 'Preset 2', value: '' } + ] + } as unknown as GuiFieldDefinition; + }); + + it('renders field name correctly', () => { + render(FieldDefinitionDropdown, { props: { fieldDefinition, gui: mockGui } }); + expect(screen.getByText('Test Field')).toBeInTheDocument(); + }); + + it('shows presets in dropdown', async () => { + render(FieldDefinitionDropdown, { props: { fieldDefinition, gui: mockGui } }); + + // Open dropdown + const dropdown = screen.getByText('Select a preset'); + await fireEvent.click(dropdown); + + // Check if presets are rendered + expect(screen.getByText('Preset 1')).toBeInTheDocument(); + expect(screen.getByText('Preset 2')).toBeInTheDocument(); + expect(screen.getByText('Custom value')).toBeInTheDocument(); + }); + + it('calls saveFieldValue when preset is selected', async () => { + render(FieldDefinitionDropdown, { props: { fieldDefinition, gui: mockGui } }); + + // Open dropdown and select preset + const dropdown = screen.getByText('Select a preset'); + await fireEvent.click(dropdown); + await fireEvent.click(screen.getByText('Preset 1')); + + expect(mockGui.saveFieldValue).toHaveBeenCalledWith('test-binding', { + isPreset: true, + value: 'preset1' + }); + }); + + it('shows input field when custom value is selected', async () => { + (mockGui.isFieldPreset as Mock).mockReturnValue(false); + + render(FieldDefinitionDropdown, { props: { fieldDefinition, gui: mockGui } }); + + // Open dropdown and select custom + const dropdown = screen.getByText('Select a preset'); + await fireEvent.click(dropdown); + await fireEvent.click(screen.getByText('Custom value')); + + // Check if input field appears + const input = screen.getByPlaceholderText('Enter value'); + expect(input).toBeInTheDocument(); + + // Test input change + await fireEvent.change(input, { target: { value: 'custom input' } }); + expect(mockGui.saveFieldValue).toHaveBeenCalledWith('test-binding', { + isPreset: false, + value: 'custom input' + }); + }); + + it('handles case when gui is not provided', () => { + render(FieldDefinitionDropdown, { props: { fieldDefinition } as FieldDefinitionDropdownProps }); + expect(screen.getByText('Test Field')).toBeInTheDocument(); + // Should not throw any errors + }); +}); diff --git a/packages/ui-components/src/__tests__/FieldDefinitionButtons.test.ts b/packages/ui-components/src/__tests__/FieldDefinitionButtons.test.ts index f8eb82e1c..acafd3066 100644 --- a/packages/ui-components/src/__tests__/FieldDefinitionButtons.test.ts +++ b/packages/ui-components/src/__tests__/FieldDefinitionButtons.test.ts @@ -6,122 +6,122 @@ import deploymentStepsStore from '../lib/components/deployment/wizard/deployment // Mock the DotrainOrderGui class vi.mock('@rainlanguage/orderbook/js_api', () => ({ - DotrainOrderGui: vi.fn().mockImplementation(() => ({ - saveFieldValue: vi.fn(), - getFieldValue: vi.fn(), - isFieldPreset: vi.fn() - })) + DotrainOrderGui: vi.fn().mockImplementation(() => ({ + saveFieldValue: vi.fn(), + getFieldValue: vi.fn(), + isFieldPreset: vi.fn() + })) })); describe('FieldDefinitionButtons', () => { - let mockGui: DotrainOrderGui; - const mockFieldDefinition = { - binding: 'test-binding', - name: 'Test Field', - description: 'Test Description', - presets: [ - { id: 'preset1', name: 'Preset 1', value: 'value1' }, - { id: 'preset2', name: 'Preset 2', value: 'value2' } - ] - }; - - beforeEach(() => { - mockGui = new DotrainOrderGui(); - vi.spyOn(deploymentStepsStore, 'updateDeploymentStep'); - }); - - it('renders field name and description', () => { - const { getByText } = render(FieldDefinitionButtons, { - props: { - fieldDefinition: mockFieldDefinition, - gui: mockGui, - currentStep: 0 - } - }); - - expect(getByText('Test Field')).toBeTruthy(); - expect(getByText('Test Description')).toBeTruthy(); - }); - - it('renders preset buttons', () => { - const { getByText } = render(FieldDefinitionButtons, { - props: { - fieldDefinition: mockFieldDefinition, - gui: mockGui, - currentStep: 0 - } - }); - - expect(getByText('Preset 1')).toBeTruthy(); - expect(getByText('Preset 2')).toBeTruthy(); - expect(getByText('Custom')).toBeTruthy(); - }); - - it('handles preset button clicks', async () => { - const { getByText } = render(FieldDefinitionButtons, { - props: { - fieldDefinition: mockFieldDefinition, - gui: mockGui, - currentStep: 0 - } - }); - - await fireEvent.click(getByText('Preset 1')); - - expect(mockGui.saveFieldValue).toHaveBeenCalledWith('test-binding', { - isPreset: true, - value: 'preset1' - }); - expect(deploymentStepsStore.updateDeploymentStep).toHaveBeenCalled(); - }); - - it('shows custom input when Custom button is clicked', async () => { - const { getByText, getByPlaceholderText } = render(FieldDefinitionButtons, { - props: { - fieldDefinition: mockFieldDefinition, - gui: mockGui, - currentStep: 0 - } - }); - - await fireEvent.click(getByText('Custom')); - expect(getByPlaceholderText('Enter custom value')).toBeTruthy(); - }); - - it('handles custom input changes', async () => { - const { getByText, getByPlaceholderText } = render(FieldDefinitionButtons, { - props: { - fieldDefinition: mockFieldDefinition, - gui: mockGui, - currentStep: 0 - } - }); - - await fireEvent.click(getByText('Custom')); - const input = getByPlaceholderText('Enter custom value'); - await fireEvent.input(input, { target: { value: 'custom value' } }); - - expect(mockGui.saveFieldValue).toHaveBeenCalledWith('test-binding', { - isPreset: false, - value: 'custom value' - }); - expect(deploymentStepsStore.updateDeploymentStep).toHaveBeenCalled(); - }); - - it('does not show Custom button for is-fast-exit binding', () => { - const fastExitFieldDef = { - ...mockFieldDefinition, - binding: 'is-fast-exit' - }; - - const { queryByText } = render(FieldDefinitionButtons, { - props: { - fieldDefinition: fastExitFieldDef, - gui: mockGui, - currentStep: 0 - } - }); - - expect(queryByText('Custom')).toBeNull(); - }); + let mockGui: DotrainOrderGui; + const mockFieldDefinition = { + binding: 'test-binding', + name: 'Test Field', + description: 'Test Description', + presets: [ + { id: 'preset1', name: 'Preset 1', value: 'value1' }, + { id: 'preset2', name: 'Preset 2', value: 'value2' } + ] + }; + + beforeEach(() => { + mockGui = new DotrainOrderGui(); + vi.spyOn(deploymentStepsStore, 'updateDeploymentStep'); + }); + + it('renders field name and description', () => { + const { getByText } = render(FieldDefinitionButtons, { + props: { + fieldDefinition: mockFieldDefinition, + gui: mockGui, + currentStep: 0 + } + }); + + expect(getByText('Test Field')).toBeTruthy(); + expect(getByText('Test Description')).toBeTruthy(); + }); + + it('renders preset buttons', () => { + const { getByText } = render(FieldDefinitionButtons, { + props: { + fieldDefinition: mockFieldDefinition, + gui: mockGui, + currentStep: 0 + } + }); + + expect(getByText('Preset 1')).toBeTruthy(); + expect(getByText('Preset 2')).toBeTruthy(); + expect(getByText('Custom')).toBeTruthy(); + }); + + it('handles preset button clicks', async () => { + const { getByText } = render(FieldDefinitionButtons, { + props: { + fieldDefinition: mockFieldDefinition, + gui: mockGui, + currentStep: 0 + } + }); + + await fireEvent.click(getByText('Preset 1')); + + expect(mockGui.saveFieldValue).toHaveBeenCalledWith('test-binding', { + isPreset: true, + value: 'preset1' + }); + expect(deploymentStepsStore.updateDeploymentStep).toHaveBeenCalled(); + }); + + it('shows custom input when Custom button is clicked', async () => { + const { getByText, getByPlaceholderText } = render(FieldDefinitionButtons, { + props: { + fieldDefinition: mockFieldDefinition, + gui: mockGui, + currentStep: 0 + } + }); + + await fireEvent.click(getByText('Custom')); + expect(getByPlaceholderText('Enter custom value')).toBeTruthy(); + }); + + it('handles custom input changes', async () => { + const { getByText, getByPlaceholderText } = render(FieldDefinitionButtons, { + props: { + fieldDefinition: mockFieldDefinition, + gui: mockGui, + currentStep: 0 + } + }); + + await fireEvent.click(getByText('Custom')); + const input = getByPlaceholderText('Enter custom value'); + await fireEvent.input(input, { target: { value: 'custom value' } }); + + expect(mockGui.saveFieldValue).toHaveBeenCalledWith('test-binding', { + isPreset: false, + value: 'custom value' + }); + expect(deploymentStepsStore.updateDeploymentStep).toHaveBeenCalled(); + }); + + it('does not show Custom button for is-fast-exit binding', () => { + const fastExitFieldDef = { + ...mockFieldDefinition, + binding: 'is-fast-exit' + }; + + const { queryByText } = render(FieldDefinitionButtons, { + props: { + fieldDefinition: fastExitFieldDef, + gui: mockGui, + currentStep: 0 + } + }); + + expect(queryByText('Custom')).toBeNull(); + }); }); diff --git a/packages/ui-components/src/__tests__/SelectToken.test.ts b/packages/ui-components/src/__tests__/SelectToken.test.ts new file mode 100644 index 000000000..86cab19cd --- /dev/null +++ b/packages/ui-components/src/__tests__/SelectToken.test.ts @@ -0,0 +1,56 @@ +import { render, fireEvent } from '@testing-library/svelte'; +import { describe, it, expect, vi, beforeEach } from 'vitest'; +import SelectToken from '../lib/components/deployment/SelectToken.svelte'; +import type { ComponentProps } from 'svelte'; +import type { DotrainOrderGui } from '@rainlanguage/orderbook/js_api'; + +export type SelectTokenComponentProps = ComponentProps; +describe('SelectToken', () => { + const mockGui: DotrainOrderGui = { + saveSelectTokenAddress: vi.fn().mockResolvedValue(undefined), + getSelectTokens: vi.fn().mockReturnValue(new Map([['TOKEN1', '0x123']])) + } as unknown as DotrainOrderGui; + + const mockProps: SelectTokenComponentProps = { + token: 'TOKEN1', + gui: mockGui, + selectTokens: new Map([['TOKEN1', '0x123']]) + }; + + beforeEach(() => { + vi.clearAllMocks(); + }); + + it('renders token label correctly', () => { + const { getByText } = render(SelectToken, mockProps); + expect(getByText('TOKEN1')).toBeInTheDocument(); + }); + + it('renders input field', () => { + const { getByRole } = render(SelectToken, mockProps); + expect(getByRole('textbox')).toBeInTheDocument(); + }); + + it('calls saveSelectTokenAddress when input changes', async () => { + const { getByRole } = render(SelectToken, mockProps); + const input = getByRole('textbox'); + + await fireEvent.change(input, { target: { value: '0x456' } }); + + expect(mockGui.saveSelectTokenAddress).toHaveBeenCalledWith('TOKEN1', '0x456'); + expect(mockGui.getSelectTokens).toHaveBeenCalled(); + }); + + it('does nothing if gui is not defined', async () => { + const { getByRole } = render(SelectToken, { + ...mockProps, + gui: undefined + } as unknown as SelectTokenComponentProps); + const input = getByRole('textbox'); + + await fireEvent.change(input, { target: { value: '0x456' } }); + + expect(mockGui.saveSelectTokenAddress).not.toHaveBeenCalled(); + expect(mockGui.getSelectTokens).not.toHaveBeenCalled(); + }); +}); diff --git a/packages/ui-components/src/__tests__/TokenInput.test.ts b/packages/ui-components/src/__tests__/TokenInput.test.ts new file mode 100644 index 000000000..8bef2556d --- /dev/null +++ b/packages/ui-components/src/__tests__/TokenInput.test.ts @@ -0,0 +1,79 @@ +import { render, fireEvent } from '@testing-library/svelte'; +import { describe, it, expect, vi, beforeEach } from 'vitest'; +import TokenInput from '../lib/components/deployment/TokenInput.svelte'; +import type { ComponentProps } from 'svelte'; + +export type TokenInputComponentProps = ComponentProps; + +describe('TokenInput', () => { + const mockTokenInfos = new Map([ + ['0x123', { symbol: 'ETH' }], + ['0x456', { symbol: 'USDC' }] + ]); + + const mockInput = { + token: { + address: '0x123' + } + }; + + const mockGui = { + setVaultId: vi.fn() + }; + + const mockProps: TokenInputComponentProps = { + i: 0, + input: mockInput, + tokenInfos: mockTokenInfos, + inputVaultIds: ['vault1'], + gui: mockGui + } as unknown as TokenInputComponentProps; + + beforeEach(() => { + vi.clearAllMocks(); + }); + + it('renders with correct label and token symbol', () => { + const { getByText } = render(TokenInput, mockProps); + expect(getByText('Input 1 (ETH)')).toBeInTheDocument(); + }); + + it('renders input field with correct placeholder', () => { + const { getByPlaceholderText } = render(TokenInput, mockProps); + const input = getByPlaceholderText('Enter vault ID'); + expect(input).toBeInTheDocument(); + }); + + it('displays the correct vault ID value', () => { + const { getByDisplayValue } = render(TokenInput, mockProps); + expect(getByDisplayValue('vault1')).toBeInTheDocument(); + }); + + it('calls setVaultId when input changes', async () => { + const { getByPlaceholderText } = render(TokenInput, mockProps); + const input = getByPlaceholderText('Enter vault ID'); + + await fireEvent.change(input, { target: { value: 'vault1' } }); + + expect(mockGui.setVaultId).toHaveBeenCalledWith(true, 0, 'vault1'); + }); + + it('does not call setVaultId when gui is undefined', async () => { + const propsWithoutGui = { ...mockProps, gui: undefined } as unknown as TokenInputComponentProps; + const { getByPlaceholderText } = render(TokenInput, propsWithoutGui); + const input = getByPlaceholderText('Enter vault ID'); + + await fireEvent.change(input, { target: { value: 'newVault' } }); + + expect(mockGui.setVaultId).not.toHaveBeenCalled(); + }); + + it('handles missing token info gracefully', () => { + const propsWithUnknownToken = { + ...mockProps, + input: { token: { address: '0x789' } } + }; + const { getByText } = render(TokenInput, propsWithUnknownToken as unknown as TokenInputComponentProps); + expect(getByText('Input 1 ()')).toBeInTheDocument(); + }); +}); \ No newline at end of file diff --git a/packages/ui-components/src/__tests__/deploymentStepsStore.test.ts b/packages/ui-components/src/__tests__/deploymentStepsStore.test.ts index e51cd8828..7dc3844d9 100644 --- a/packages/ui-components/src/__tests__/deploymentStepsStore.test.ts +++ b/packages/ui-components/src/__tests__/deploymentStepsStore.test.ts @@ -1,106 +1,104 @@ import { get } from 'svelte/store'; -import deploymentStepsStore from '../lib/components/deployment/wizard/deploymentStepsStore' +import deploymentStepsStore from '../lib/components/deployment/wizard/deploymentStepsStore'; import type { WizardStep, TokenInputStep, FieldStep } from '../lib/types/wizardSteps'; describe('deploymentStepsStore', () => { - beforeEach(() => { - deploymentStepsStore.reset(); - }); + beforeEach(() => { + deploymentStepsStore.reset(); + }); - it('should initialize with empty array', () => { - const steps = get(deploymentStepsStore); - expect(steps).toEqual([]); - }); + it('should initialize with empty array', () => { + const steps = get(deploymentStepsStore); + expect(steps).toEqual([]); + }); - it('should populate steps correctly', () => { - const mockSteps: WizardStep[] = [ - { - type: 'tokenInput', - input: { - token: '0x123...', - decimals: 18, - symbol: 'TEST' - }, - gui: { - name: 'Test GUI', - description: 'Test Description', - }, - tokenInfos: { - }, - i: 0, - inputVaultIds: ['vault1', 'vault2'] - } as unknown as TokenInputStep, - { - type: 'fields', - fieldDefinition: { - name: 'Test Field', - type: 'uint256', - }, - gui: { - name: 'Test GUI', - description: 'Test Description', - } - } as unknown as FieldStep - ]; + it('should populate steps correctly', () => { + const mockSteps: WizardStep[] = [ + { + type: 'tokenInput', + input: { + token: '0x123...', + decimals: 18, + symbol: 'TEST' + }, + gui: { + name: 'Test GUI', + description: 'Test Description' + }, + tokenInfos: {}, + i: 0, + inputVaultIds: ['vault1', 'vault2'] + } as unknown as TokenInputStep, + { + type: 'fields', + fieldDefinition: { + name: 'Test Field', + type: 'uint256' + }, + gui: { + name: 'Test GUI', + description: 'Test Description' + } + } as unknown as FieldStep + ]; - deploymentStepsStore.populateDeploymentSteps(mockSteps); - const steps = get(deploymentStepsStore); + deploymentStepsStore.populateDeploymentSteps(mockSteps); + const steps = get(deploymentStepsStore); - expect(steps).toEqual(mockSteps); - }); + expect(steps).toEqual(mockSteps); + }); - it('should update a specific step correctly', () => { - const initialSteps: WizardStep[] = [ - { - type: 'tokenInput', - input: { - token: '0x123...', - decimals: 18, - symbol: 'TEST' - }, - gui: { - name: 'Test GUI', - description: 'Test Description' - }, - tokenInfos: { - }, - i: 0, - inputVaultIds: ['vault1'] - } as unknown as TokenInputStep - ]; + it('should update a specific step correctly', () => { + const initialSteps: WizardStep[] = [ + { + type: 'tokenInput', + input: { + token: '0x123...', + decimals: 18, + symbol: 'TEST' + }, + gui: { + name: 'Test GUI', + description: 'Test Description' + }, + tokenInfos: {}, + i: 0, + inputVaultIds: ['vault1'] + } as unknown as TokenInputStep + ]; - deploymentStepsStore.populateDeploymentSteps(initialSteps); + deploymentStepsStore.populateDeploymentSteps(initialSteps); - const updatedStep: TokenInputStep = { - ...initialSteps[0], - inputVaultIds: ['vault1', 'vault2'] - } as unknown as TokenInputStep; + const updatedStep: TokenInputStep = { + ...initialSteps[0], + inputVaultIds: ['vault1', 'vault2'] + } as unknown as TokenInputStep; - deploymentStepsStore.updateDeploymentStep(0, updatedStep); + deploymentStepsStore.updateDeploymentStep(0, updatedStep); - const steps = get(deploymentStepsStore); - expect(steps[0]).toEqual(updatedStep); - }); + const steps = get(deploymentStepsStore); + expect(steps[0]).toEqual(updatedStep); + }); - it('should reset store to initial state', () => { - const mockSteps: WizardStep[] = [ - { - type: 'fields', - fieldDefinition: { - name: 'Test Field', - type: 'uint256', - }, - gui: { - name: 'Test GUI', - description: 'Test Description', - } - } as unknown as FieldStep - ]; + it('should reset store to initial state', () => { + const mockSteps: WizardStep[] = [ + { + type: 'fields', + fieldDefinition: { + name: 'Test Field', + type: 'uint256' + }, + gui: { + name: 'Test GUI', + description: 'Test Description' + } + } as unknown as FieldStep + ]; - deploymentStepsStore.populateDeploymentSteps(mockSteps); - deploymentStepsStore.reset(); + deploymentStepsStore.populateDeploymentSteps(mockSteps); + deploymentStepsStore.reset(); - const steps = get(deploymentStepsStore); - expect(steps).toEqual([]); - }); -}); \ No newline at end of file + const steps = get(deploymentStepsStore); + expect(steps).toEqual([]); + }); +}); diff --git a/packages/ui-components/src/__tests__/getDeploymentSteps.test.ts b/packages/ui-components/src/__tests__/getDeploymentSteps.test.ts index c1b7fc9b0..a1d3b92ea 100644 --- a/packages/ui-components/src/__tests__/getDeploymentSteps.test.ts +++ b/packages/ui-components/src/__tests__/getDeploymentSteps.test.ts @@ -3,96 +3,96 @@ import { getDeploymentSteps } from '../lib/components/deployment/wizard/getDeplo import { describe, it, expect } from 'vitest'; describe('getDeploymentSteps', () => { - const mockGui = {} as any; - const mockTokenInfos = {} as any; + const mockGui = {} as any; + const mockTokenInfos = {} as any; - it('should return empty array when no inputs provided', () => { - const steps = getDeploymentSteps( - new Map(), - false, - [], - mockGui, - [], - [], - [], - [], - [], - mockTokenInfos - ); + it('should return empty array when no inputs provided', () => { + const steps = getDeploymentSteps( + new Map(), + false, + [], + mockGui, + [], + [], + [], + [], + [], + mockTokenInfos + ); - expect(steps).toEqual([]); - }); + expect(steps).toEqual([]); + }); - it('should include select token steps for limit strategy', () => { - const selectTokens = new Map([['TOKEN1', 'address1']]); + it('should include select token steps for limit strategy', () => { + const selectTokens = new Map([['TOKEN1', 'address1']]); - const steps = getDeploymentSteps( - selectTokens, - true, - [], - mockGui, - [], - [], - [], - [], - [], - mockTokenInfos - ); + const steps = getDeploymentSteps( + selectTokens, + true, + [], + mockGui, + [], + [], + [], + [], + [], + mockTokenInfos + ); - expect(steps[0]).toEqual({ - type: 'tokens', - token: 'TOKEN1', - gui: mockGui, - selectTokens - }); - }); + expect(steps[0]).toEqual({ + type: 'tokens', + token: 'TOKEN1', + gui: mockGui, + selectTokens + }); + }); - it('should not include select token steps when not limit strategy', () => { - const selectTokens = new Map([['TOKEN1', 'address1']]); + it('should not include select token steps when not limit strategy', () => { + const selectTokens = new Map([['TOKEN1', 'address1']]); - const steps = getDeploymentSteps( - selectTokens, - false, - [], - mockGui, - [], - [], - [], - [], - [], - mockTokenInfos - ); + const steps = getDeploymentSteps( + selectTokens, + false, + [], + mockGui, + [], + [], + [], + [], + [], + mockTokenInfos + ); - expect(steps).toEqual([]); - }); + expect(steps).toEqual([]); + }); - it('should include all step types in correct order', () => { - const selectTokens = new Map([['TOKEN1', 'address1']]); - const fieldDefinitions = [{ id: 'field1' }] as any; - const deposits = [{ id: 'deposit1' }] as any; - const inputs = [{ id: 'input1' }] as any; - const outputs = [{ id: 'output1' }] as any; - const inputVaultIds = ['vault1']; - const outputVaultIds = ['vault2']; + it('should include all step types in correct order', () => { + const selectTokens = new Map([['TOKEN1', 'address1']]); + const fieldDefinitions = [{ id: 'field1' }] as any; + const deposits = [{ id: 'deposit1' }] as any; + const inputs = [{ id: 'input1' }] as any; + const outputs = [{ id: 'output1' }] as any; + const inputVaultIds = ['vault1']; + const outputVaultIds = ['vault2']; - const steps = getDeploymentSteps( - selectTokens, - true, - fieldDefinitions, - mockGui, - deposits, - inputs, - outputs, - inputVaultIds, - outputVaultIds, - mockTokenInfos - ); + const steps = getDeploymentSteps( + selectTokens, + true, + fieldDefinitions, + mockGui, + deposits, + inputs, + outputs, + inputVaultIds, + outputVaultIds, + mockTokenInfos + ); - expect(steps).toHaveLength(5); - expect(steps[0].type).toBe('tokens'); - expect(steps[1].type).toBe('fields'); - expect(steps[2].type).toBe('deposits'); - expect(steps[3].type).toBe('tokenInput'); - expect(steps[4].type).toBe('tokenOutput'); - }); -}); \ No newline at end of file + expect(steps).toHaveLength(5); + expect(steps[0].type).toBe('tokens'); + expect(steps[1].type).toBe('fields'); + expect(steps[2].type).toBe('deposits'); + expect(steps[3].type).toBe('tokenInput'); + expect(steps[4].type).toBe('tokenOutput'); + }); +}); diff --git a/packages/ui-components/src/lib/components/deployment/TokenInput.svelte b/packages/ui-components/src/lib/components/deployment/TokenInput.svelte index 863e0291e..1e7e0c4b6 100644 --- a/packages/ui-components/src/lib/components/deployment/TokenInput.svelte +++ b/packages/ui-components/src/lib/components/deployment/TokenInput.svelte @@ -12,7 +12,7 @@
Input {i + 1} ({tokenInfos.get(input.token.address)?.symbol || ''})
diff --git a/packages/ui-components/src/lib/components/deployment/wizard/deploymentStepsStore.ts b/packages/ui-components/src/lib/components/deployment/wizard/deploymentStepsStore.ts index e857d41a6..9801f6857 100644 --- a/packages/ui-components/src/lib/components/deployment/wizard/deploymentStepsStore.ts +++ b/packages/ui-components/src/lib/components/deployment/wizard/deploymentStepsStore.ts @@ -1,24 +1,24 @@ import { writable } from 'svelte/store'; import type { WizardStep } from '../../../types/wizardSteps'; -const initialState: WizardStep[] = [] +const initialState: WizardStep[] = []; const deploymentStepsStore = () => { const { subscribe, set, update } = writable(initialState); - const reset = () => set(initialState); + const reset = () => set(initialState); - // For getting an array of steps from the various input types (deposit, token, vault) + // For getting an array of steps from the various input types (deposit, token, vault) const populateDeploymentSteps = (steps: WizardStep[]) => { - update(() => ( steps )); + update(() => steps); }; - // For adding a property (binding) to the current step + // For adding a property (binding) to the current step const updateDeploymentStep = (index: number, updatedStep: WizardStep) => { - update((state) => { - const newSteps = [...state]; - newSteps[index] = updatedStep; - return newSteps - }); + update((state) => { + const newSteps = [...state]; + newSteps[index] = updatedStep; + return newSteps; + }); }; return { diff --git a/packages/ui-components/src/lib/components/deployment/wizard/getDeploymentSteps.ts b/packages/ui-components/src/lib/components/deployment/wizard/getDeploymentSteps.ts index 5f55f31f4..b48b259ef 100644 --- a/packages/ui-components/src/lib/components/deployment/wizard/getDeploymentSteps.ts +++ b/packages/ui-components/src/lib/components/deployment/wizard/getDeploymentSteps.ts @@ -1,10 +1,16 @@ -import type { TokenOutputStep } from "$lib/types/wizardSteps"; +import type { TokenOutputStep } from '$lib/types/wizardSteps'; -import type { DepositStep, FieldStep, TokenInputStep } from "$lib/types/wizardSteps"; +import type { DepositStep, FieldStep, TokenInputStep } from '$lib/types/wizardSteps'; -import type { SelectTokenStep } from "$lib/types/wizardSteps"; +import type { SelectTokenStep } from '$lib/types/wizardSteps'; -import type { DotrainOrderGui, GuiFieldDefinition, TokenInfos, Vault, TokenDeposit} from '@rainlanguage/orderbook/js_api'; +import type { + DotrainOrderGui, + GuiFieldDefinition, + TokenInfos, + Vault, + TokenDeposit +} from '@rainlanguage/orderbook/js_api'; import type { WizardStep } from '../../../types/wizardSteps'; export const getDeploymentSteps = ( @@ -64,13 +70,12 @@ export const getDeploymentSteps = ( type: 'tokenOutput', output, gui, - tokenInfos, - i, - outputVaultIds + tokenInfos, + i, + outputVaultIds }) ) ]; return deploymentSteps; }; - diff --git a/packages/ui-components/src/lib/types/wizardSteps.ts b/packages/ui-components/src/lib/types/wizardSteps.ts index 0729e498e..6ff7f776d 100644 --- a/packages/ui-components/src/lib/types/wizardSteps.ts +++ b/packages/ui-components/src/lib/types/wizardSteps.ts @@ -51,4 +51,9 @@ export interface TokenOutputStep extends BaseWizardStep { outputVaultIds: string[]; } -export type WizardStep = SelectTokenStep | FieldStep | DepositStep | TokenInputStep | TokenOutputStep; +export type WizardStep = + | SelectTokenStep + | FieldStep + | DepositStep + | TokenInputStep + | TokenOutputStep; From c435a4cc991cd9b9c4b1c633449cb664c9b40783 Mon Sep 17 00:00:00 2001 From: Jamie Harding Date: Fri, 27 Dec 2024 15:42:40 +0100 Subject: [PATCH 019/142] add test --- .../src/__tests__/DepositDropdown.test.ts | 95 +++++++++++++++++++ 1 file changed, 95 insertions(+) create mode 100644 packages/ui-components/src/__tests__/DepositDropdown.test.ts diff --git a/packages/ui-components/src/__tests__/DepositDropdown.test.ts b/packages/ui-components/src/__tests__/DepositDropdown.test.ts new file mode 100644 index 000000000..1c2678892 --- /dev/null +++ b/packages/ui-components/src/__tests__/DepositDropdown.test.ts @@ -0,0 +1,95 @@ +import { describe, it, expect, vi } from 'vitest'; +import { render, fireEvent } from '@testing-library/svelte'; +import DepositDropdown from '../lib/components/deployment/DepositDropdown.svelte'; +import type { DotrainOrderGui, GuiDeposit } from '@rainlanguage/orderbook/js_api'; + +describe('DepositDropdown', () => { + const mockTokenInfos = new Map(); + mockTokenInfos.set('0x123', { name: 'Test Token' }); + + const mockDeposit: GuiDeposit = { + token: { address: '0x123' }, + token_name: 'TEST', + presets: ['100', '200', '300'] + } as unknown as GuiDeposit; + + const mockGui = { + saveDeposit: vi.fn(), + isDepositPreset: vi.fn() + }; + + it('renders token name correctly', () => { + const { getByText } = render(DepositDropdown, { + props: { + deposit: mockDeposit, + gui: mockGui as unknown as DotrainOrderGui, + tokenInfos: mockTokenInfos + } + }); + + expect(getByText('Test Token')).toBeTruthy(); + }); + + it('shows "Choose deposit amount" by default', () => { + const { getByText } = render(DepositDropdown, { + props: { + deposit: mockDeposit, + gui: mockGui as unknown as DotrainOrderGui, + tokenInfos: mockTokenInfos + } + }); + + expect(getByText('Choose deposit amount')).toBeTruthy(); + }); + + it('calls saveDeposit when preset is selected', async () => { + mockGui.isDepositPreset.mockReturnValue(true); + + const { getByText } = render(DepositDropdown, { + props: { + deposit: mockDeposit, + gui: mockGui as unknown as DotrainOrderGui, + tokenInfos: mockTokenInfos + } + }); + + await fireEvent.click(getByText('Choose deposit amount')); + await fireEvent.click(getByText('100')); + + expect(mockGui.saveDeposit).toHaveBeenCalledWith('TEST', '100'); + }); + + it('shows input field when custom value is selected', async () => { + mockGui.isDepositPreset.mockReturnValue(false); + + const { getByText, getByPlaceholderText } = render(DepositDropdown, { + props: { + deposit: mockDeposit, + gui: mockGui as unknown as DotrainOrderGui, + tokenInfos: mockTokenInfos + } + }); + + await fireEvent.click(getByText('Choose deposit amount')); + await fireEvent.click(getByText('Custom value')); + + expect(getByPlaceholderText('Enter deposit amount')).toBeTruthy(); + }); + + it('calls saveDeposit when custom value is entered', async () => { + mockGui.isDepositPreset.mockReturnValue(false); + + const { getByPlaceholderText } = render(DepositDropdown, { + props: { + deposit: mockDeposit, + gui: mockGui as unknown as DotrainOrderGui, + tokenInfos: mockTokenInfos + } + }); + + const input = getByPlaceholderText('Enter deposit amount'); + await fireEvent.change(input, { target: { value: '150' } }); + + expect(mockGui.saveDeposit).toHaveBeenCalledWith('TEST', '150'); + }); +}); \ No newline at end of file From 33ba188107a202d8cb565937bee24cae49883744 Mon Sep 17 00:00:00 2001 From: Jamie Harding Date: Fri, 27 Dec 2024 15:49:44 +0100 Subject: [PATCH 020/142] test depositButtons.test. --- .../src/__tests__/DepositButtons.test.ts | 88 +++++++++++++++++++ .../deployment/wizard/DeploymentSteps.svelte | 4 +- 2 files changed, 90 insertions(+), 2 deletions(-) create mode 100644 packages/ui-components/src/__tests__/DepositButtons.test.ts diff --git a/packages/ui-components/src/__tests__/DepositButtons.test.ts b/packages/ui-components/src/__tests__/DepositButtons.test.ts new file mode 100644 index 000000000..cb67694fe --- /dev/null +++ b/packages/ui-components/src/__tests__/DepositButtons.test.ts @@ -0,0 +1,88 @@ +import { describe, it, expect, vi, beforeEach } from 'vitest'; +import { render, fireEvent } from '@testing-library/svelte'; +import DepositButtons from '../lib/components/deployment/wizard/DepositButtons.svelte'; +import type { GuiDeposit } from '@rainlanguage/orderbook/js_api'; +import type { ComponentProps } from 'svelte'; + +type DepositButtonsProps = ComponentProps; + +describe('DepositButtons', () => { + const mockGui = { + isDepositPreset: vi.fn(), + saveDeposit: vi.fn() + }; + + const mockTokenInfos = new Map([ + ['0x123', { name: 'Test Token', symbol: 'TEST' }] + ]); + + const mockDeposit: GuiDeposit = { + token: { address: '0x123' }, + token_name: 'TEST', + presets: ['100', '200', '300'] + } as unknown as GuiDeposit + + beforeEach(() => { + vi.clearAllMocks(); + }); + + it('renders token name and presets', () => { + const { getByText } = render(DepositButtons, { + props: { + deposit: mockDeposit, + gui: mockGui, + tokenInfos: mockTokenInfos + } as unknown as DepositButtonsProps + }); + + expect(getByText('Test Token')).toBeTruthy(); + expect(getByText('100')).toBeTruthy(); + expect(getByText('200')).toBeTruthy(); + expect(getByText('300')).toBeTruthy(); + expect(getByText('Custom')).toBeTruthy(); + }); + + it('handles preset button clicks', async () => { + const { getByText } = render(DepositButtons, { + props: { + deposit: mockDeposit, + gui: mockGui, + tokenInfos: mockTokenInfos + } as unknown as DepositButtonsProps + }); + + await fireEvent.click(getByText('100')); + expect(mockGui.saveDeposit).toHaveBeenCalledWith('TEST', '100'); + }); + + it('shows custom input when Custom button is clicked', async () => { + const { getByText, getByPlaceholderText } = render(DepositButtons, { + props: { + deposit: mockDeposit, + gui: mockGui, + tokenInfos: mockTokenInfos + } as unknown as DepositButtonsProps + }); + + await fireEvent.click(getByText('Custom')); + expect(getByPlaceholderText('Enter deposit amount')).toBeTruthy(); + expect(mockGui.saveDeposit).toHaveBeenCalledWith('TEST', ''); + }); + + it('handles custom input changes', async () => { + mockGui.isDepositPreset.mockReturnValue(false); + + const { getByPlaceholderText } = render(DepositButtons, { + props: { + deposit: mockDeposit, + gui: mockGui, + tokenInfos: mockTokenInfos + } as unknown as DepositButtonsProps + }); + + const input = getByPlaceholderText('Enter deposit amount'); + await fireEvent.input(input, { target: { value: '150' } }); + + expect(mockGui.saveDeposit).toHaveBeenCalledWith('TEST', '150'); + }); +}); \ No newline at end of file diff --git a/packages/ui-components/src/lib/components/deployment/wizard/DeploymentSteps.svelte b/packages/ui-components/src/lib/components/deployment/wizard/DeploymentSteps.svelte index c03ea68c6..6616eac27 100644 --- a/packages/ui-components/src/lib/components/deployment/wizard/DeploymentSteps.svelte +++ b/packages/ui-components/src/lib/components/deployment/wizard/DeploymentSteps.svelte @@ -7,7 +7,7 @@ import type { DotrainOrderGui, - GuiDeposit, + TokenDeposit, GuiFieldDefinition, SelectTokens, TokenInfos, @@ -22,7 +22,7 @@ export let allFieldDefinitions: GuiFieldDefinition[]; export let allTokenInputs: Vault[]; export let allTokenOutputs: Vault[]; - export let allDeposits: GuiDeposit[]; + export let allDeposits: TokenDeposit[]; export let inputVaultIds: string[]; export let outputVaultIds: string[]; export let isLimitStrat: boolean; From a77e6d4b28890b32abf4c2a2f20bf05e1ec94bce Mon Sep 17 00:00:00 2001 From: Jamie Harding Date: Thu, 2 Jan 2025 11:19:02 +0100 Subject: [PATCH 021/142] format --- .vscode/settings.json | 2 + .../src/__tests__/DepositButtons.test.ts | 130 +++++++------ .../src/__tests__/DepositDropdown.test.ts | 178 +++++++++--------- .../src/__tests__/TokenInput.test.ts | 145 +++++++------- .../deployment/wizard/DeploymentSteps.svelte | 44 ++--- .../wizard/FieldDefinitionButtons.svelte | 13 +- .../src/lib/types/wizardSteps.ts | 20 +- 7 files changed, 267 insertions(+), 265 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 237f93c57..606cd4bee 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -3,6 +3,8 @@ "svelte.enable-ts-plugin": true, "rust-analyzer.linkedProjects": ["./Cargo.toml", "tauri-app/src-tauri/Cargo.toml"], + "rust-analyzer.cargo.target": "wasm32-unknown-unknown", + "[rust]": { "editor.defaultFormatter": "rust-lang.rust-analyzer", "editor.formatOnSave": true, diff --git a/packages/ui-components/src/__tests__/DepositButtons.test.ts b/packages/ui-components/src/__tests__/DepositButtons.test.ts index cb67694fe..da6a4196b 100644 --- a/packages/ui-components/src/__tests__/DepositButtons.test.ts +++ b/packages/ui-components/src/__tests__/DepositButtons.test.ts @@ -7,82 +7,80 @@ import type { ComponentProps } from 'svelte'; type DepositButtonsProps = ComponentProps; describe('DepositButtons', () => { - const mockGui = { - isDepositPreset: vi.fn(), - saveDeposit: vi.fn() - }; + const mockGui = { + isDepositPreset: vi.fn(), + saveDeposit: vi.fn() + }; - const mockTokenInfos = new Map([ - ['0x123', { name: 'Test Token', symbol: 'TEST' }] - ]); + const mockTokenInfos = new Map([['0x123', { name: 'Test Token', symbol: 'TEST' }]]); - const mockDeposit: GuiDeposit = { - token: { address: '0x123' }, - token_name: 'TEST', - presets: ['100', '200', '300'] - } as unknown as GuiDeposit + const mockDeposit: GuiDeposit = { + token: { address: '0x123' }, + token_name: 'TEST', + presets: ['100', '200', '300'] + } as unknown as GuiDeposit; - beforeEach(() => { - vi.clearAllMocks(); - }); + beforeEach(() => { + vi.clearAllMocks(); + }); - it('renders token name and presets', () => { - const { getByText } = render(DepositButtons, { - props: { - deposit: mockDeposit, - gui: mockGui, - tokenInfos: mockTokenInfos - } as unknown as DepositButtonsProps - }); + it('renders token name and presets', () => { + const { getByText } = render(DepositButtons, { + props: { + deposit: mockDeposit, + gui: mockGui, + tokenInfos: mockTokenInfos + } as unknown as DepositButtonsProps + }); - expect(getByText('Test Token')).toBeTruthy(); - expect(getByText('100')).toBeTruthy(); - expect(getByText('200')).toBeTruthy(); - expect(getByText('300')).toBeTruthy(); - expect(getByText('Custom')).toBeTruthy(); - }); + expect(getByText('Test Token')).toBeTruthy(); + expect(getByText('100')).toBeTruthy(); + expect(getByText('200')).toBeTruthy(); + expect(getByText('300')).toBeTruthy(); + expect(getByText('Custom')).toBeTruthy(); + }); - it('handles preset button clicks', async () => { - const { getByText } = render(DepositButtons, { - props: { - deposit: mockDeposit, - gui: mockGui, - tokenInfos: mockTokenInfos - } as unknown as DepositButtonsProps - }); + it('handles preset button clicks', async () => { + const { getByText } = render(DepositButtons, { + props: { + deposit: mockDeposit, + gui: mockGui, + tokenInfos: mockTokenInfos + } as unknown as DepositButtonsProps + }); - await fireEvent.click(getByText('100')); - expect(mockGui.saveDeposit).toHaveBeenCalledWith('TEST', '100'); - }); + await fireEvent.click(getByText('100')); + expect(mockGui.saveDeposit).toHaveBeenCalledWith('TEST', '100'); + }); - it('shows custom input when Custom button is clicked', async () => { - const { getByText, getByPlaceholderText } = render(DepositButtons, { - props: { - deposit: mockDeposit, - gui: mockGui, - tokenInfos: mockTokenInfos - } as unknown as DepositButtonsProps - }); + it('shows custom input when Custom button is clicked', async () => { + const { getByText, getByPlaceholderText } = render(DepositButtons, { + props: { + deposit: mockDeposit, + gui: mockGui, + tokenInfos: mockTokenInfos + } as unknown as DepositButtonsProps + }); - await fireEvent.click(getByText('Custom')); - expect(getByPlaceholderText('Enter deposit amount')).toBeTruthy(); - expect(mockGui.saveDeposit).toHaveBeenCalledWith('TEST', ''); - }); + await fireEvent.click(getByText('Custom')); + expect(getByPlaceholderText('Enter deposit amount')).toBeTruthy(); + expect(mockGui.saveDeposit).toHaveBeenCalledWith('TEST', ''); + }); - it('handles custom input changes', async () => { - mockGui.isDepositPreset.mockReturnValue(false); + it('handles custom input changes', async () => { + mockGui.isDepositPreset.mockReturnValue(false); - const { getByPlaceholderText } = render(DepositButtons, { - props: { - deposit: mockDeposit, - gui: mockGui, - tokenInfos: mockTokenInfos - } as unknown as DepositButtonsProps - }); + const { getByPlaceholderText } = render(DepositButtons, { + props: { + deposit: mockDeposit, + gui: mockGui, + tokenInfos: mockTokenInfos + } as unknown as DepositButtonsProps + }); - const input = getByPlaceholderText('Enter deposit amount'); - await fireEvent.input(input, { target: { value: '150' } }); + const input = getByPlaceholderText('Enter deposit amount'); + await fireEvent.input(input, { target: { value: '150' } }); - expect(mockGui.saveDeposit).toHaveBeenCalledWith('TEST', '150'); - }); -}); \ No newline at end of file + expect(mockGui.saveDeposit).toHaveBeenCalledWith('TEST', '150'); + }); +}); diff --git a/packages/ui-components/src/__tests__/DepositDropdown.test.ts b/packages/ui-components/src/__tests__/DepositDropdown.test.ts index 1c2678892..960e27e15 100644 --- a/packages/ui-components/src/__tests__/DepositDropdown.test.ts +++ b/packages/ui-components/src/__tests__/DepositDropdown.test.ts @@ -4,92 +4,92 @@ import DepositDropdown from '../lib/components/deployment/DepositDropdown.svelte import type { DotrainOrderGui, GuiDeposit } from '@rainlanguage/orderbook/js_api'; describe('DepositDropdown', () => { - const mockTokenInfos = new Map(); - mockTokenInfos.set('0x123', { name: 'Test Token' }); - - const mockDeposit: GuiDeposit = { - token: { address: '0x123' }, - token_name: 'TEST', - presets: ['100', '200', '300'] - } as unknown as GuiDeposit; - - const mockGui = { - saveDeposit: vi.fn(), - isDepositPreset: vi.fn() - }; - - it('renders token name correctly', () => { - const { getByText } = render(DepositDropdown, { - props: { - deposit: mockDeposit, - gui: mockGui as unknown as DotrainOrderGui, - tokenInfos: mockTokenInfos - } - }); - - expect(getByText('Test Token')).toBeTruthy(); - }); - - it('shows "Choose deposit amount" by default', () => { - const { getByText } = render(DepositDropdown, { - props: { - deposit: mockDeposit, - gui: mockGui as unknown as DotrainOrderGui, - tokenInfos: mockTokenInfos - } - }); - - expect(getByText('Choose deposit amount')).toBeTruthy(); - }); - - it('calls saveDeposit when preset is selected', async () => { - mockGui.isDepositPreset.mockReturnValue(true); - - const { getByText } = render(DepositDropdown, { - props: { - deposit: mockDeposit, - gui: mockGui as unknown as DotrainOrderGui, - tokenInfos: mockTokenInfos - } - }); - - await fireEvent.click(getByText('Choose deposit amount')); - await fireEvent.click(getByText('100')); - - expect(mockGui.saveDeposit).toHaveBeenCalledWith('TEST', '100'); - }); - - it('shows input field when custom value is selected', async () => { - mockGui.isDepositPreset.mockReturnValue(false); - - const { getByText, getByPlaceholderText } = render(DepositDropdown, { - props: { - deposit: mockDeposit, - gui: mockGui as unknown as DotrainOrderGui, - tokenInfos: mockTokenInfos - } - }); - - await fireEvent.click(getByText('Choose deposit amount')); - await fireEvent.click(getByText('Custom value')); - - expect(getByPlaceholderText('Enter deposit amount')).toBeTruthy(); - }); - - it('calls saveDeposit when custom value is entered', async () => { - mockGui.isDepositPreset.mockReturnValue(false); - - const { getByPlaceholderText } = render(DepositDropdown, { - props: { - deposit: mockDeposit, - gui: mockGui as unknown as DotrainOrderGui, - tokenInfos: mockTokenInfos - } - }); - - const input = getByPlaceholderText('Enter deposit amount'); - await fireEvent.change(input, { target: { value: '150' } }); - - expect(mockGui.saveDeposit).toHaveBeenCalledWith('TEST', '150'); - }); -}); \ No newline at end of file + const mockTokenInfos = new Map(); + mockTokenInfos.set('0x123', { name: 'Test Token' }); + + const mockDeposit: GuiDeposit = { + token: { address: '0x123' }, + token_name: 'TEST', + presets: ['100', '200', '300'] + } as unknown as GuiDeposit; + + const mockGui = { + saveDeposit: vi.fn(), + isDepositPreset: vi.fn() + }; + + it('renders token name correctly', () => { + const { getByText } = render(DepositDropdown, { + props: { + deposit: mockDeposit, + gui: mockGui as unknown as DotrainOrderGui, + tokenInfos: mockTokenInfos + } + }); + + expect(getByText('Test Token')).toBeTruthy(); + }); + + it('shows "Choose deposit amount" by default', () => { + const { getByText } = render(DepositDropdown, { + props: { + deposit: mockDeposit, + gui: mockGui as unknown as DotrainOrderGui, + tokenInfos: mockTokenInfos + } + }); + + expect(getByText('Choose deposit amount')).toBeTruthy(); + }); + + it('calls saveDeposit when preset is selected', async () => { + mockGui.isDepositPreset.mockReturnValue(true); + + const { getByText } = render(DepositDropdown, { + props: { + deposit: mockDeposit, + gui: mockGui as unknown as DotrainOrderGui, + tokenInfos: mockTokenInfos + } + }); + + await fireEvent.click(getByText('Choose deposit amount')); + await fireEvent.click(getByText('100')); + + expect(mockGui.saveDeposit).toHaveBeenCalledWith('TEST', '100'); + }); + + it('shows input field when custom value is selected', async () => { + mockGui.isDepositPreset.mockReturnValue(false); + + const { getByText, getByPlaceholderText } = render(DepositDropdown, { + props: { + deposit: mockDeposit, + gui: mockGui as unknown as DotrainOrderGui, + tokenInfos: mockTokenInfos + } + }); + + await fireEvent.click(getByText('Choose deposit amount')); + await fireEvent.click(getByText('Custom value')); + + expect(getByPlaceholderText('Enter deposit amount')).toBeTruthy(); + }); + + it('calls saveDeposit when custom value is entered', async () => { + mockGui.isDepositPreset.mockReturnValue(false); + + const { getByPlaceholderText } = render(DepositDropdown, { + props: { + deposit: mockDeposit, + gui: mockGui as unknown as DotrainOrderGui, + tokenInfos: mockTokenInfos + } + }); + + const input = getByPlaceholderText('Enter deposit amount'); + await fireEvent.change(input, { target: { value: '150' } }); + + expect(mockGui.saveDeposit).toHaveBeenCalledWith('TEST', '150'); + }); +}); diff --git a/packages/ui-components/src/__tests__/TokenInput.test.ts b/packages/ui-components/src/__tests__/TokenInput.test.ts index 8bef2556d..8457fa66a 100644 --- a/packages/ui-components/src/__tests__/TokenInput.test.ts +++ b/packages/ui-components/src/__tests__/TokenInput.test.ts @@ -6,74 +6,77 @@ import type { ComponentProps } from 'svelte'; export type TokenInputComponentProps = ComponentProps; describe('TokenInput', () => { - const mockTokenInfos = new Map([ - ['0x123', { symbol: 'ETH' }], - ['0x456', { symbol: 'USDC' }] - ]); - - const mockInput = { - token: { - address: '0x123' - } - }; - - const mockGui = { - setVaultId: vi.fn() - }; - - const mockProps: TokenInputComponentProps = { - i: 0, - input: mockInput, - tokenInfos: mockTokenInfos, - inputVaultIds: ['vault1'], - gui: mockGui - } as unknown as TokenInputComponentProps; - - beforeEach(() => { - vi.clearAllMocks(); - }); - - it('renders with correct label and token symbol', () => { - const { getByText } = render(TokenInput, mockProps); - expect(getByText('Input 1 (ETH)')).toBeInTheDocument(); - }); - - it('renders input field with correct placeholder', () => { - const { getByPlaceholderText } = render(TokenInput, mockProps); - const input = getByPlaceholderText('Enter vault ID'); - expect(input).toBeInTheDocument(); - }); - - it('displays the correct vault ID value', () => { - const { getByDisplayValue } = render(TokenInput, mockProps); - expect(getByDisplayValue('vault1')).toBeInTheDocument(); - }); - - it('calls setVaultId when input changes', async () => { - const { getByPlaceholderText } = render(TokenInput, mockProps); - const input = getByPlaceholderText('Enter vault ID'); - - await fireEvent.change(input, { target: { value: 'vault1' } }); - - expect(mockGui.setVaultId).toHaveBeenCalledWith(true, 0, 'vault1'); - }); - - it('does not call setVaultId when gui is undefined', async () => { - const propsWithoutGui = { ...mockProps, gui: undefined } as unknown as TokenInputComponentProps; - const { getByPlaceholderText } = render(TokenInput, propsWithoutGui); - const input = getByPlaceholderText('Enter vault ID'); - - await fireEvent.change(input, { target: { value: 'newVault' } }); - - expect(mockGui.setVaultId).not.toHaveBeenCalled(); - }); - - it('handles missing token info gracefully', () => { - const propsWithUnknownToken = { - ...mockProps, - input: { token: { address: '0x789' } } - }; - const { getByText } = render(TokenInput, propsWithUnknownToken as unknown as TokenInputComponentProps); - expect(getByText('Input 1 ()')).toBeInTheDocument(); - }); -}); \ No newline at end of file + const mockTokenInfos = new Map([ + ['0x123', { symbol: 'ETH' }], + ['0x456', { symbol: 'USDC' }] + ]); + + const mockInput = { + token: { + address: '0x123' + } + }; + + const mockGui = { + setVaultId: vi.fn() + }; + + const mockProps: TokenInputComponentProps = { + i: 0, + input: mockInput, + tokenInfos: mockTokenInfos, + inputVaultIds: ['vault1'], + gui: mockGui + } as unknown as TokenInputComponentProps; + + beforeEach(() => { + vi.clearAllMocks(); + }); + + it('renders with correct label and token symbol', () => { + const { getByText } = render(TokenInput, mockProps); + expect(getByText('Input 1 (ETH)')).toBeInTheDocument(); + }); + + it('renders input field with correct placeholder', () => { + const { getByPlaceholderText } = render(TokenInput, mockProps); + const input = getByPlaceholderText('Enter vault ID'); + expect(input).toBeInTheDocument(); + }); + + it('displays the correct vault ID value', () => { + const { getByDisplayValue } = render(TokenInput, mockProps); + expect(getByDisplayValue('vault1')).toBeInTheDocument(); + }); + + it('calls setVaultId when input changes', async () => { + const { getByPlaceholderText } = render(TokenInput, mockProps); + const input = getByPlaceholderText('Enter vault ID'); + + await fireEvent.change(input, { target: { value: 'vault1' } }); + + expect(mockGui.setVaultId).toHaveBeenCalledWith(true, 0, 'vault1'); + }); + + it('does not call setVaultId when gui is undefined', async () => { + const propsWithoutGui = { ...mockProps, gui: undefined } as unknown as TokenInputComponentProps; + const { getByPlaceholderText } = render(TokenInput, propsWithoutGui); + const input = getByPlaceholderText('Enter vault ID'); + + await fireEvent.change(input, { target: { value: 'newVault' } }); + + expect(mockGui.setVaultId).not.toHaveBeenCalled(); + }); + + it('handles missing token info gracefully', () => { + const propsWithUnknownToken = { + ...mockProps, + input: { token: { address: '0x789' } } + }; + const { getByText } = render( + TokenInput, + propsWithUnknownToken as unknown as TokenInputComponentProps + ); + expect(getByText('Input 1 ()')).toBeInTheDocument(); + }); +}); diff --git a/packages/ui-components/src/lib/components/deployment/wizard/DeploymentSteps.svelte b/packages/ui-components/src/lib/components/deployment/wizard/DeploymentSteps.svelte index 6616eac27..5587ad356 100644 --- a/packages/ui-components/src/lib/components/deployment/wizard/DeploymentSteps.svelte +++ b/packages/ui-components/src/lib/components/deployment/wizard/DeploymentSteps.svelte @@ -7,7 +7,7 @@ import type { DotrainOrderGui, - TokenDeposit, + GuiDeposit, GuiFieldDefinition, SelectTokens, TokenInfos, @@ -22,7 +22,7 @@ export let allFieldDefinitions: GuiFieldDefinition[]; export let allTokenInputs: Vault[]; export let allTokenOutputs: Vault[]; - export let allDeposits: TokenDeposit[]; + export let allDeposits: GuiDeposit[]; export let inputVaultIds: string[]; export let outputVaultIds: string[]; export let isLimitStrat: boolean; @@ -45,50 +45,52 @@ deploymentStepsStore.populateDeploymentSteps(deploymentSteps); - $: currentStep = 0; + $: currentStepIndex = 0; const nextStep = () => { - if (currentStep < deploymentSteps.length - 1) { - currentStep++; + if (currentStepIndex < deploymentSteps.length - 1) { + currentStepIndex++; } }; const previousStep = () => { - if (currentStep > 0) { - currentStep--; + if (currentStepIndex > 0) { + currentStepIndex--; } }; + + $: currentStep = deploymentSteps[currentStepIndex];
- Step {currentStep + 1} of {deploymentSteps.length} + Step {currentStepIndex + 1} of {deploymentSteps.length}
- {#if deploymentSteps[currentStep].type === 'tokens'} - - {:else if deploymentSteps[currentStep].type === 'fields'} - - {:else if deploymentSteps[currentStep].type === 'deposits'} - - {:else if deploymentSteps[currentStep].type === 'tokenInput'} - - {:else if deploymentSteps[currentStep].type === 'tokenOutput'} - + {#if currentStep.type === 'tokens'} + + {:else if currentStep.type === 'fields'} + + {:else if currentStep.type === 'deposits'} + + {:else if currentStep.type === 'tokenInput'} + + {:else if currentStep.type === 'tokenOutput'} + {/if}
- {#if currentStep > 0} + {#if currentStepIndex > 0} {/if} - {#if currentStep === deploymentSteps.length - 1} + {#if currentStepIndex === deploymentSteps.length - 1} {:else} diff --git a/packages/ui-components/src/lib/components/deployment/wizard/FieldDefinitionButtons.svelte b/packages/ui-components/src/lib/components/deployment/wizard/FieldDefinitionButtons.svelte index 422c690e5..471ff1ab2 100644 --- a/packages/ui-components/src/lib/components/deployment/wizard/FieldDefinitionButtons.svelte +++ b/packages/ui-components/src/lib/components/deployment/wizard/FieldDefinitionButtons.svelte @@ -1,12 +1,13 @@ + +
+ + gui?.setVaultId(true, i, outputVaultIds[i])} + /> +
diff --git a/packages/ui-components/src/lib/components/deployment/wizard/DeploymentSteps.svelte b/packages/ui-components/src/lib/components/deployment/wizard/DeploymentSteps.svelte index 5587ad356..00e2a6bdf 100644 --- a/packages/ui-components/src/lib/components/deployment/wizard/DeploymentSteps.svelte +++ b/packages/ui-components/src/lib/components/deployment/wizard/DeploymentSteps.svelte @@ -70,7 +70,7 @@ {#if currentStep.type === 'tokens'} {:else if currentStep.type === 'fields'} - + {:else if currentStep.type === 'deposits'} {:else if currentStep.type === 'tokenInput'} diff --git a/packages/ui-components/src/lib/components/deployment/wizard/getDeploymentSteps.ts b/packages/ui-components/src/lib/components/deployment/wizard/getDeploymentSteps.ts index b48b259ef..354def4ee 100644 --- a/packages/ui-components/src/lib/components/deployment/wizard/getDeploymentSteps.ts +++ b/packages/ui-components/src/lib/components/deployment/wizard/getDeploymentSteps.ts @@ -9,7 +9,7 @@ import type { GuiFieldDefinition, TokenInfos, Vault, - TokenDeposit + GuiDeposit } from '@rainlanguage/orderbook/js_api'; import type { WizardStep } from '../../../types/wizardSteps'; @@ -18,7 +18,7 @@ export const getDeploymentSteps = ( isLimitStrat: boolean, allFieldDefinitions: GuiFieldDefinition[], gui: DotrainOrderGui, - allDeposits: TokenDeposit[], + allDeposits: GuiDeposit[], allTokenInputs: Vault[], allTokenOutputs: Vault[], inputVaultIds: string[], diff --git a/packages/ui-components/src/lib/types/wizardSteps.ts b/packages/ui-components/src/lib/types/wizardSteps.ts index cde983234..f900670d8 100644 --- a/packages/ui-components/src/lib/types/wizardSteps.ts +++ b/packages/ui-components/src/lib/types/wizardSteps.ts @@ -4,8 +4,8 @@ import type { GuiFieldDefinition, TokenInfos, Vault, - TokenDeposit, - GuiPreset + GuiPreset, + GuiDeposit } from '@rainlanguage/orderbook/js_api'; export interface SelectTokenStep { @@ -24,7 +24,7 @@ export interface FieldStep { export interface DepositStep { type: 'deposits'; - deposit: TokenDeposit; + deposit: GuiDeposit; gui: DotrainOrderGui; tokenInfos: TokenInfos; } diff --git a/tauri-app/src/tests/pickConfig.test.ts b/tauri-app/src/tests/pickConfig.test.ts index 96532bf24..2e4b36044 100644 --- a/tauri-app/src/tests/pickConfig.test.ts +++ b/tauri-app/src/tests/pickConfig.test.ts @@ -48,7 +48,6 @@ export const config: Config = { tokens: {}, orders: { buy: { - key: 'buy', inputs: [], outputs: [], network: { @@ -58,7 +57,6 @@ export const config: Config = { }, }, sell: { - key: 'sell', inputs: [], outputs: [], network: { @@ -126,7 +124,6 @@ export const config: Config = { }, }, order: { - key: 'sell', inputs: [], outputs: [], network: { @@ -151,7 +148,6 @@ export const config: Config = { }, }, order: { - key: 'buy', inputs: [], outputs: [], network: { From 996ab5166c87ea6fb0c7a37aec59af4ec9f83f76 Mon Sep 17 00:00:00 2001 From: Jamie Harding Date: Thu, 2 Jan 2025 12:15:51 +0100 Subject: [PATCH 023/142] poutput --- packages/ui-components/src/lib/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ui-components/src/lib/index.ts b/packages/ui-components/src/lib/index.ts index 01a33a489..61260247e 100644 --- a/packages/ui-components/src/lib/index.ts +++ b/packages/ui-components/src/lib/index.ts @@ -52,7 +52,7 @@ export { default as FieldDefinitionButtons } from './components/deployment/wizar export { default as DepositButtons } from './components/deployment/wizard/DepositButtons.svelte'; export { default as DeploymentSteps } from './components/deployment/wizard/DeploymentSteps.svelte'; export { default as TokenInput } from './components/deployment/TokenInput.svelte'; -export { default as TokenOutput } from './components/deployment/wizard/TokenOutputButtons.svelte'; +export { default as TokenOutput } from './components/deployment/TokenOutput.svelte'; export { default as SelectToken } from './components/deployment/SelectToken.svelte'; export { default as TokenInputButtons } from './components/deployment/wizard/TokenInputButtons.svelte'; export { default as TokenOutputButtons } from './components/deployment/wizard/TokenOutputButtons.svelte'; From 462706aca1e5d20e54af1a86abe8b3b5aedd9f0a Mon Sep 17 00:00:00 2001 From: Jamie Harding Date: Thu, 2 Jan 2025 12:39:44 +0100 Subject: [PATCH 024/142] types and format --- .../__tests__/FieldDefinitionButtons.test.ts | 42 ++++++++++++++++--- .../deployment/wizard/DeploymentSteps.svelte | 5 +-- .../wizard/TokenInputButtons.svelte | 3 -- .../wizard/TokenOutputButtons.svelte | 3 -- .../deployment/wizard/getDeploymentSteps.ts | 4 ++ .../webapp/src/routes/deployment/+page.svelte | 4 +- .../src/routes/deployment/new/+page.svelte | 3 -- 7 files changed, 43 insertions(+), 21 deletions(-) diff --git a/packages/ui-components/src/__tests__/FieldDefinitionButtons.test.ts b/packages/ui-components/src/__tests__/FieldDefinitionButtons.test.ts index acafd3066..2b92a9a0c 100644 --- a/packages/ui-components/src/__tests__/FieldDefinitionButtons.test.ts +++ b/packages/ui-components/src/__tests__/FieldDefinitionButtons.test.ts @@ -35,7 +35,12 @@ describe('FieldDefinitionButtons', () => { props: { fieldDefinition: mockFieldDefinition, gui: mockGui, - currentStep: 0 + currentStepIndex: 0, + currentStep: { + type: 'fields', + fieldDefinition: mockFieldDefinition, + gui: mockGui + } } }); @@ -48,7 +53,12 @@ describe('FieldDefinitionButtons', () => { props: { fieldDefinition: mockFieldDefinition, gui: mockGui, - currentStep: 0 + currentStepIndex: 0, + currentStep: { + type: 'fields', + fieldDefinition: mockFieldDefinition, + gui: mockGui + } } }); @@ -62,7 +72,12 @@ describe('FieldDefinitionButtons', () => { props: { fieldDefinition: mockFieldDefinition, gui: mockGui, - currentStep: 0 + currentStepIndex: 0, + currentStep: { + type: 'fields', + fieldDefinition: mockFieldDefinition, + gui: mockGui + } } }); @@ -80,7 +95,12 @@ describe('FieldDefinitionButtons', () => { props: { fieldDefinition: mockFieldDefinition, gui: mockGui, - currentStep: 0 + currentStepIndex: 0, + currentStep: { + type: 'fields', + fieldDefinition: mockFieldDefinition, + gui: mockGui + } } }); @@ -93,7 +113,12 @@ describe('FieldDefinitionButtons', () => { props: { fieldDefinition: mockFieldDefinition, gui: mockGui, - currentStep: 0 + currentStepIndex: 0, + currentStep: { + type: 'fields', + fieldDefinition: mockFieldDefinition, + gui: mockGui + } } }); @@ -118,7 +143,12 @@ describe('FieldDefinitionButtons', () => { props: { fieldDefinition: fastExitFieldDef, gui: mockGui, - currentStep: 0 + currentStepIndex: 0, + currentStep: { + type: 'fields', + fieldDefinition: fastExitFieldDef, + gui: mockGui + } } }); diff --git a/packages/ui-components/src/lib/components/deployment/wizard/DeploymentSteps.svelte b/packages/ui-components/src/lib/components/deployment/wizard/DeploymentSteps.svelte index 00e2a6bdf..24bd09d7c 100644 --- a/packages/ui-components/src/lib/components/deployment/wizard/DeploymentSteps.svelte +++ b/packages/ui-components/src/lib/components/deployment/wizard/DeploymentSteps.svelte @@ -26,7 +26,6 @@ export let inputVaultIds: string[]; export let outputVaultIds: string[]; export let isLimitStrat: boolean; - export let useCustomVaultIds: boolean; export let handleAddOrder: () => Promise; export let tokenInfos: TokenInfos; @@ -74,9 +73,9 @@ {:else if currentStep.type === 'deposits'} {:else if currentStep.type === 'tokenInput'} - + {:else if currentStep.type === 'tokenOutput'} - + {/if}
diff --git a/packages/ui-components/src/lib/components/deployment/wizard/TokenInputButtons.svelte b/packages/ui-components/src/lib/components/deployment/wizard/TokenInputButtons.svelte index dc06732cc..325bff678 100644 --- a/packages/ui-components/src/lib/components/deployment/wizard/TokenInputButtons.svelte +++ b/packages/ui-components/src/lib/components/deployment/wizard/TokenInputButtons.svelte @@ -1,15 +1,12 @@
diff --git a/packages/ui-components/src/lib/components/deployment/wizard/TokenOutputButtons.svelte b/packages/ui-components/src/lib/components/deployment/wizard/TokenOutputButtons.svelte index 696251fee..c153afd29 100644 --- a/packages/ui-components/src/lib/components/deployment/wizard/TokenOutputButtons.svelte +++ b/packages/ui-components/src/lib/components/deployment/wizard/TokenOutputButtons.svelte @@ -1,15 +1,12 @@
diff --git a/packages/ui-components/src/lib/components/deployment/wizard/getDeploymentSteps.ts b/packages/ui-components/src/lib/components/deployment/wizard/getDeploymentSteps.ts index 354def4ee..7afdc8f94 100644 --- a/packages/ui-components/src/lib/components/deployment/wizard/getDeploymentSteps.ts +++ b/packages/ui-components/src/lib/components/deployment/wizard/getDeploymentSteps.ts @@ -13,6 +13,10 @@ import type { } from '@rainlanguage/orderbook/js_api'; import type { WizardStep } from '../../../types/wizardSteps'; +// TODO: Add a check to see if the user has selected to use custom token input/outputs +// If they have, then we need to add a step to the wizard to allow them to enter the vault ids +// If they have not, then we can skip this step + export const getDeploymentSteps = ( selectTokens: Map, isLimitStrat: boolean, diff --git a/packages/webapp/src/routes/deployment/+page.svelte b/packages/webapp/src/routes/deployment/+page.svelte index 71326c693..cf125fbb9 100644 --- a/packages/webapp/src/routes/deployment/+page.svelte +++ b/packages/webapp/src/routes/deployment/+page.svelte @@ -239,9 +239,7 @@ {/if} {#if allFieldDefinitions.length > 0} - + {#each allFieldDefinitions as fieldDefinition} {/each} diff --git a/packages/webapp/src/routes/deployment/new/+page.svelte b/packages/webapp/src/routes/deployment/new/+page.svelte index 60ed18dc4..ff41fa0e5 100644 --- a/packages/webapp/src/routes/deployment/new/+page.svelte +++ b/packages/webapp/src/routes/deployment/new/+page.svelte @@ -177,7 +177,6 @@ } } - let useCustomVaultIds = false; let inputVaultIds: string[] = []; let outputVaultIds: string[] = []; function initializeVaultIdArrays() { @@ -185,7 +184,6 @@ const deployment = gui.getCurrentDeployment(); inputVaultIds = new Array(deployment.deployment.order.inputs.length).fill(''); outputVaultIds = new Array(deployment.deployment.order.outputs.length).fill(''); - useCustomVaultIds = false; } @@ -226,7 +224,6 @@ Date: Fri, 3 Jan 2025 09:53:25 +0100 Subject: [PATCH 025/142] simplifying steps --- .../components/deployment/TokenInput.svelte | 23 ---- ...utput.svelte => TokenInputOrOutput.svelte} | 13 +- .../deployment/wizard/DeploymentSteps.svelte | 113 ++++++++---------- .../wizard/FieldDefinitionButtons.svelte | 18 +-- .../wizard/TokenInputButtons.svelte | 29 ----- .../wizard/TokenInputOrOutputWizard.svelte | 32 +++++ .../wizard/TokenOutputButtons.svelte | 22 ---- .../deployment/wizard/deploymentStepsStore.ts | 32 ----- .../deployment/wizard/getDeploymentSteps.ts | 85 ------------- packages/ui-components/src/lib/index.ts | 16 +-- .../src/lib/types/deploymentSteps.ts | 82 ------------- .../src/lib/types/wizardSteps.ts | 55 --------- .../webapp/src/routes/deployment/+page.svelte | 21 +++- 13 files changed, 108 insertions(+), 433 deletions(-) delete mode 100644 packages/ui-components/src/lib/components/deployment/TokenInput.svelte rename packages/ui-components/src/lib/components/deployment/{TokenOutput.svelte => TokenInputOrOutput.svelte} (59%) delete mode 100644 packages/ui-components/src/lib/components/deployment/wizard/TokenInputButtons.svelte create mode 100644 packages/ui-components/src/lib/components/deployment/wizard/TokenInputOrOutputWizard.svelte delete mode 100644 packages/ui-components/src/lib/components/deployment/wizard/TokenOutputButtons.svelte delete mode 100644 packages/ui-components/src/lib/components/deployment/wizard/deploymentStepsStore.ts delete mode 100644 packages/ui-components/src/lib/components/deployment/wizard/getDeploymentSteps.ts delete mode 100644 packages/ui-components/src/lib/types/deploymentSteps.ts delete mode 100644 packages/ui-components/src/lib/types/wizardSteps.ts diff --git a/packages/ui-components/src/lib/components/deployment/TokenInput.svelte b/packages/ui-components/src/lib/components/deployment/TokenInput.svelte deleted file mode 100644 index 1e7e0c4b6..000000000 --- a/packages/ui-components/src/lib/components/deployment/TokenInput.svelte +++ /dev/null @@ -1,23 +0,0 @@ - - -
- - gui?.setVaultId(true, i, inputVaultIds[i])} - /> -
diff --git a/packages/ui-components/src/lib/components/deployment/TokenOutput.svelte b/packages/ui-components/src/lib/components/deployment/TokenInputOrOutput.svelte similarity index 59% rename from packages/ui-components/src/lib/components/deployment/TokenOutput.svelte rename to packages/ui-components/src/lib/components/deployment/TokenInputOrOutput.svelte index bf93078f9..9a71e581b 100644 --- a/packages/ui-components/src/lib/components/deployment/TokenOutput.svelte +++ b/packages/ui-components/src/lib/components/deployment/TokenInputOrOutput.svelte @@ -4,20 +4,21 @@ import type { DotrainOrderGui } from '@rainlanguage/orderbook/js_api'; export let i: number; - export let output: Vault; + export let label: 'Input' | 'Output'; + export let vault: Vault; export let tokenInfos: TokenInfos; - export let outputVaultIds: string[]; + export let vaultIds: string[]; export let gui: DotrainOrderGui; -
+
{label} {i + 1} ({tokenInfos.get(vault.token.address)?.symbol || ''}) gui?.setVaultId(true, i, outputVaultIds[i])} + bind:value={vaultIds[i]} + on:change={() => gui?.setVaultId(true, i, vaultIds[i])} />
diff --git a/packages/ui-components/src/lib/components/deployment/wizard/DeploymentSteps.svelte b/packages/ui-components/src/lib/components/deployment/wizard/DeploymentSteps.svelte index 24bd09d7c..9422382a4 100644 --- a/packages/ui-components/src/lib/components/deployment/wizard/DeploymentSteps.svelte +++ b/packages/ui-components/src/lib/components/deployment/wizard/DeploymentSteps.svelte @@ -2,8 +2,7 @@ import FieldDefinitionButtons from './FieldDefinitionButtons.svelte'; import DepositButtons from './DepositButtons.svelte'; import SelectToken from '../SelectToken.svelte'; - import TokenInputButtons from './TokenInputButtons.svelte'; - import TokenOutputButtons from './TokenOutputButtons.svelte'; + import TokenInputOrOutputWizard from './TokenInputOrOutputWizard.svelte'; import type { DotrainOrderGui, @@ -13,9 +12,7 @@ TokenInfos, Vault } from '@rainlanguage/orderbook/js_api'; - import { Button } from 'flowbite-svelte'; - import { getDeploymentSteps } from './getDeploymentSteps'; - import deploymentStepsStore from './deploymentStepsStore'; + import { Button, Label } from 'flowbite-svelte'; export let gui: DotrainOrderGui; export let selectTokens: SelectTokens; @@ -28,71 +25,57 @@ export let isLimitStrat: boolean; export let handleAddOrder: () => Promise; export let tokenInfos: TokenInfos; - - let deploymentSteps = getDeploymentSteps( - selectTokens, - isLimitStrat, - allFieldDefinitions, - gui, - allDeposits, - allTokenInputs, - allTokenOutputs, - inputVaultIds, - outputVaultIds, - tokenInfos - ); - - deploymentStepsStore.populateDeploymentSteps(deploymentSteps); - - $: currentStepIndex = 0; - - const nextStep = () => { - if (currentStepIndex < deploymentSteps.length - 1) { - currentStepIndex++; - } - }; - - const previousStep = () => { - if (currentStepIndex > 0) { - currentStepIndex--; - } - }; - - $: currentStep = deploymentSteps[currentStepIndex];
-
- Step {currentStepIndex + 1} of {deploymentSteps.length} -
+ {#if isLimitStrat && selectTokens.size > 0} + - {#if currentStep.type === 'tokens'} - - {:else if currentStep.type === 'fields'} - - {:else if currentStep.type === 'deposits'} - - {:else if currentStep.type === 'tokenInput'} - - {:else if currentStep.type === 'tokenOutput'} - + {#each selectTokens.entries() as [token]} + + {/each} {/if} -
- {#if currentStepIndex > 0} - - {/if} + {#if allFieldDefinitions.length > 0} + + {#each allFieldDefinitions as fieldDefinition} + + {/each} + {/if} + + {#if allDeposits.length > 0} + + {#each allDeposits as deposit} + + {/each} + {/if} - {#if currentStepIndex === deploymentSteps.length - 1} - - {:else} - - {/if} -
+ {#if allTokenInputs.length > 0} + + {#each allTokenInputs as input, i} + + {/each} + {/if} + + {#if allTokenOutputs.length > 0} + + {#each allTokenOutputs as output, i} + + {/each} + {/if} +
diff --git a/packages/ui-components/src/lib/components/deployment/wizard/FieldDefinitionButtons.svelte b/packages/ui-components/src/lib/components/deployment/wizard/FieldDefinitionButtons.svelte index 471ff1ab2..23780abc3 100644 --- a/packages/ui-components/src/lib/components/deployment/wizard/FieldDefinitionButtons.svelte +++ b/packages/ui-components/src/lib/components/deployment/wizard/FieldDefinitionButtons.svelte @@ -1,13 +1,10 @@ - -
-
-

- Input {i + 1} ({tokenInfos.get(input.token.address)?.symbol}) -

-

Enter vault ID

-
- -
- gui?.setVaultId(true, i, inputVaultIds[i])} - /> -
-
diff --git a/packages/ui-components/src/lib/components/deployment/wizard/TokenInputOrOutputWizard.svelte b/packages/ui-components/src/lib/components/deployment/wizard/TokenInputOrOutputWizard.svelte new file mode 100644 index 000000000..88e8ce13c --- /dev/null +++ b/packages/ui-components/src/lib/components/deployment/wizard/TokenInputOrOutputWizard.svelte @@ -0,0 +1,32 @@ + + +
+ +
+

+ {label} + {i + 1} ({tokenInfos.get(vault.token.address)?.symbol || ''}) +

+
+
+ gui?.setVaultId(true, i, vaultIds[i])} + /> +
+
diff --git a/packages/ui-components/src/lib/components/deployment/wizard/TokenOutputButtons.svelte b/packages/ui-components/src/lib/components/deployment/wizard/TokenOutputButtons.svelte deleted file mode 100644 index c153afd29..000000000 --- a/packages/ui-components/src/lib/components/deployment/wizard/TokenOutputButtons.svelte +++ /dev/null @@ -1,22 +0,0 @@ - - -
- - gui?.setVaultId(false, i, outputVaultIds[i])} - /> -
diff --git a/packages/ui-components/src/lib/components/deployment/wizard/deploymentStepsStore.ts b/packages/ui-components/src/lib/components/deployment/wizard/deploymentStepsStore.ts deleted file mode 100644 index 9801f6857..000000000 --- a/packages/ui-components/src/lib/components/deployment/wizard/deploymentStepsStore.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { writable } from 'svelte/store'; -import type { WizardStep } from '../../../types/wizardSteps'; - -const initialState: WizardStep[] = []; - -const deploymentStepsStore = () => { - const { subscribe, set, update } = writable(initialState); - const reset = () => set(initialState); - - // For getting an array of steps from the various input types (deposit, token, vault) - const populateDeploymentSteps = (steps: WizardStep[]) => { - update(() => steps); - }; - - // For adding a property (binding) to the current step - const updateDeploymentStep = (index: number, updatedStep: WizardStep) => { - update((state) => { - const newSteps = [...state]; - newSteps[index] = updatedStep; - return newSteps; - }); - }; - - return { - subscribe, - reset, - updateDeploymentStep, - populateDeploymentSteps - }; -}; - -export default deploymentStepsStore(); diff --git a/packages/ui-components/src/lib/components/deployment/wizard/getDeploymentSteps.ts b/packages/ui-components/src/lib/components/deployment/wizard/getDeploymentSteps.ts deleted file mode 100644 index 7afdc8f94..000000000 --- a/packages/ui-components/src/lib/components/deployment/wizard/getDeploymentSteps.ts +++ /dev/null @@ -1,85 +0,0 @@ -import type { TokenOutputStep } from '$lib/types/wizardSteps'; - -import type { DepositStep, FieldStep, TokenInputStep } from '$lib/types/wizardSteps'; - -import type { SelectTokenStep } from '$lib/types/wizardSteps'; - -import type { - DotrainOrderGui, - GuiFieldDefinition, - TokenInfos, - Vault, - GuiDeposit -} from '@rainlanguage/orderbook/js_api'; -import type { WizardStep } from '../../../types/wizardSteps'; - -// TODO: Add a check to see if the user has selected to use custom token input/outputs -// If they have, then we need to add a step to the wizard to allow them to enter the vault ids -// If they have not, then we can skip this step - -export const getDeploymentSteps = ( - selectTokens: Map, - isLimitStrat: boolean, - allFieldDefinitions: GuiFieldDefinition[], - gui: DotrainOrderGui, - allDeposits: GuiDeposit[], - allTokenInputs: Vault[], - allTokenOutputs: Vault[], - inputVaultIds: string[], - outputVaultIds: string[], - tokenInfos: TokenInfos -) => { - const deploymentSteps: WizardStep[] = [ - ...(selectTokens.size > 0 && isLimitStrat - ? Array.from(selectTokens.entries()).map( - ([token]): SelectTokenStep => ({ - type: 'tokens', - token, - gui, - selectTokens - }) - ) - : []), - - ...allFieldDefinitions.map( - (fieldDefinition): FieldStep => ({ - type: 'fields', - fieldDefinition, - gui - }) - ), - - ...allDeposits.map( - (deposit): DepositStep => ({ - type: 'deposits', - deposit, - gui, - tokenInfos - }) - ), - - ...allTokenInputs.map( - (input, i): TokenInputStep => ({ - type: 'tokenInput', - input, - gui, - tokenInfos, - i, - inputVaultIds - }) - ), - - ...allTokenOutputs.map( - (output, i): TokenOutputStep => ({ - type: 'tokenOutput', - output, - gui, - tokenInfos, - i, - outputVaultIds - }) - ) - ]; - - return deploymentSteps; -}; diff --git a/packages/ui-components/src/lib/index.ts b/packages/ui-components/src/lib/index.ts index 61260247e..32b826af9 100644 --- a/packages/ui-components/src/lib/index.ts +++ b/packages/ui-components/src/lib/index.ts @@ -51,24 +51,14 @@ export { default as DepositDropdown } from './components/deployment/DepositDropd export { default as FieldDefinitionButtons } from './components/deployment/wizard/FieldDefinitionButtons.svelte'; export { default as DepositButtons } from './components/deployment/wizard/DepositButtons.svelte'; export { default as DeploymentSteps } from './components/deployment/wizard/DeploymentSteps.svelte'; -export { default as TokenInput } from './components/deployment/TokenInput.svelte'; -export { default as TokenOutput } from './components/deployment/TokenOutput.svelte'; +export { default as TokenInputOrOutput } from './components/deployment/TokenInputOrOutput.svelte'; +export { default as TokenOutput } from './components/deployment/TokenInputOrOutput.svelte'; export { default as SelectToken } from './components/deployment/SelectToken.svelte'; -export { default as TokenInputButtons } from './components/deployment/wizard/TokenInputButtons.svelte'; -export { default as TokenOutputButtons } from './components/deployment/wizard/TokenOutputButtons.svelte'; export { default as InputToken } from './components/input/InputToken.svelte'; - +export { default as TokenInputOrOutputWizard } from './components/deployment/wizard/TokenInputOrOutputWizard.svelte'; //Types export type { AppStoresInterface } from './types/appStores.ts'; export type { ConfigSource, OrderbookConfigSource, OrderbookRef } from './typeshare/config'; -export type { - WizardStep, - SelectTokenStep, - FieldStep, - DepositStep, - TokenInputStep, - TokenOutputStep -} from './types/wizardSteps'; // Functions export { createResolvableQuery, createResolvableInfiniteQuery } from './__mocks__/queries'; diff --git a/packages/ui-components/src/lib/types/deploymentSteps.ts b/packages/ui-components/src/lib/types/deploymentSteps.ts deleted file mode 100644 index 00c17b7f9..000000000 --- a/packages/ui-components/src/lib/types/deploymentSteps.ts +++ /dev/null @@ -1,82 +0,0 @@ -export type DeploymentStep = { - label: string; - type: 'tokens' | 'fields' | 'deposits' | 'vaults'; - fields: any[]; // Changed from 'items' to 'fields' -}; - -// Example object: -const exampleDeploymentSteps = { - selectTokens: { - label: 'Select Tokens', - type: 'tokens', - fields: [ - { token: 'USDC', address: '0x0000000000000000000000000000000000000000' }, - { token: 'WETH', address: '0x0000000000000000000000000000000000000000' } - ] - }, - fieldDefinitions: { - label: 'Field Values', - type: 'fields', - fields: [ - { - name: 'Price', - binding: 'price', - presets: [ - { id: 'preset1', name: 'Market Price' }, - { id: 'preset2', name: 'Custom Price' } - ] - }, - { - name: 'Amount', - binding: 'amount', - presets: [ - { id: 'small', name: 'Small' }, - { id: 'medium', name: 'Medium' }, - { id: 'large', name: 'Large' } - ] - } - ] - }, - deposits: { - label: 'Deposits', - type: 'deposits', - fields: [ - { - token_name: 'USDC', - token: { - address: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48', - name: 'USD Coin', - symbol: 'USDC', - decimals: 6 - }, - presets: ['100', '1000', '10000'] - } - ] - }, - vaults: { - label: 'Vault IDs', - type: 'vaults', - fields: [ - { - type: 'input', - index: 0, - id: '1', - tokenInfo: { - name: 'USD Coin', - symbol: 'USDC', - decimals: 6 - } - }, - { - type: 'output', - index: 0, - id: '2', - tokenInfo: { - name: 'Wrapped Ether', - symbol: 'WETH', - decimals: 18 - } - } - ] - } -}; diff --git a/packages/ui-components/src/lib/types/wizardSteps.ts b/packages/ui-components/src/lib/types/wizardSteps.ts deleted file mode 100644 index f900670d8..000000000 --- a/packages/ui-components/src/lib/types/wizardSteps.ts +++ /dev/null @@ -1,55 +0,0 @@ -import type { - DotrainOrderGui, - SelectTokens, - GuiFieldDefinition, - TokenInfos, - Vault, - GuiPreset, - GuiDeposit -} from '@rainlanguage/orderbook/js_api'; - -export interface SelectTokenStep { - type: 'tokens'; - token: string; - gui: DotrainOrderGui; - selectTokens: SelectTokens; -} - -export interface FieldStep { - type: 'fields'; - fieldDefinition: GuiFieldDefinition; - gui: DotrainOrderGui; - fieldValue?: GuiPreset; -} - -export interface DepositStep { - type: 'deposits'; - deposit: GuiDeposit; - gui: DotrainOrderGui; - tokenInfos: TokenInfos; -} - -export interface TokenInputStep { - type: 'tokenInput'; - input: Vault; - gui: DotrainOrderGui; - tokenInfos: TokenInfos; - i: number; - inputVaultIds: string[]; -} - -export interface TokenOutputStep { - type: 'tokenOutput'; - output: Vault; - gui: DotrainOrderGui; - tokenInfos: TokenInfos; - i: number; - outputVaultIds: string[]; -} - -export type WizardStep = - | SelectTokenStep - | FieldStep - | DepositStep - | TokenInputStep - | TokenOutputStep; diff --git a/packages/webapp/src/routes/deployment/+page.svelte b/packages/webapp/src/routes/deployment/+page.svelte index cf125fbb9..f91bfac32 100644 --- a/packages/webapp/src/routes/deployment/+page.svelte +++ b/packages/webapp/src/routes/deployment/+page.svelte @@ -4,8 +4,7 @@ Checkbox, FieldDefinitionDropdown, DepositDropdown, - TokenInput, - TokenOutput, + TokenInputOrOutput, SelectToken } from '@rainlanguage/ui-components'; import { @@ -264,14 +263,28 @@ {#if allTokenInputs.length > 0} {#each allTokenInputs as input, i} - + {/each} {/if} {#if allTokenOutputs.length > 0} {#each allTokenOutputs as output, i} - + {/each} {/if} {/if} From b24172fd7a5c95f3374bc78105b43fb62da780b1 Mon Sep 17 00:00:00 2001 From: Jamie Harding Date: Fri, 3 Jan 2025 10:08:15 +0100 Subject: [PATCH 026/142] fleex row --- .../src/lib/components/deployment/TokenInputOrOutput.svelte | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ui-components/src/lib/components/deployment/TokenInputOrOutput.svelte b/packages/ui-components/src/lib/components/deployment/TokenInputOrOutput.svelte index 9a71e581b..12c0d956a 100644 --- a/packages/ui-components/src/lib/components/deployment/TokenInputOrOutput.svelte +++ b/packages/ui-components/src/lib/components/deployment/TokenInputOrOutput.svelte @@ -11,7 +11,7 @@ export let gui: DotrainOrderGui; -
+
From 86f6ea4f7cf0605272ec9353554b98a801af50a9 Mon Sep 17 00:00:00 2001 From: Jamie Harding Date: Fri, 3 Jan 2025 10:11:56 +0100 Subject: [PATCH 027/142] remove setting --- .vscode/settings.json | 1 - 1 file changed, 1 deletion(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 606cd4bee..b8dfff267 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -3,7 +3,6 @@ "svelte.enable-ts-plugin": true, "rust-analyzer.linkedProjects": ["./Cargo.toml", "tauri-app/src-tauri/Cargo.toml"], - "rust-analyzer.cargo.target": "wasm32-unknown-unknown", "[rust]": { "editor.defaultFormatter": "rust-lang.rust-analyzer", From d4bc35246317a0da1ed0ee9646405d824da9524c Mon Sep 17 00:00:00 2001 From: Jamie Harding Date: Fri, 3 Jan 2025 10:50:36 +0100 Subject: [PATCH 028/142] fix tests --- packages/orderbook/test/js_api/vault.test.ts | 62 +++++------ .../__tests__/FieldDefinitionButtons.test.ts | 52 +-------- ...put.test.ts => TokenInputOrOutput.test.ts} | 36 +++--- .../__tests__/deploymentStepsStore.test.ts | 104 ------------------ .../src/__tests__/getDeploymentSteps.test.ts | 98 ----------------- .../deployment/TokenInputOrOutput.svelte | 2 +- .../wizard/TokenInputOrOutputWizard.svelte | 3 +- packages/ui-components/src/lib/index.ts | 3 +- 8 files changed, 59 insertions(+), 301 deletions(-) rename packages/ui-components/src/__tests__/{TokenInput.test.ts => TokenInputOrOutput.test.ts} (60%) delete mode 100644 packages/ui-components/src/__tests__/deploymentStepsStore.test.ts delete mode 100644 packages/ui-components/src/__tests__/getDeploymentSteps.test.ts diff --git a/packages/orderbook/test/js_api/vault.test.ts b/packages/orderbook/test/js_api/vault.test.ts index ee8fe9509..e057e7d83 100644 --- a/packages/orderbook/test/js_api/vault.test.ts +++ b/packages/orderbook/test/js_api/vault.test.ts @@ -94,32 +94,32 @@ describe('Rain Orderbook JS API Package Bindgen Vault Tests', async function () it('should fetch vault balance changes', async () => { const mockVaultBalanceChanges = [ { - "__typename": "Deposit", - "amount": "5000000000000000000", - "newVaultBalance": "5000000000000000000", - "oldVaultBalance": "0", - "vault": { - "id": "0x166aeed725f0f3ef9fe62f2a9054035756d55e5560b17afa1ae439e9cd362902", - "vaultId": "1", - "token": { - "id": "0x1d80c49bbbcd1c0911346656b529df9e5c2f783d", - "address": "0x1d80c49bbbcd1c0911346656b529df9e5c2f783d", - "name": "Wrapped Flare", - "symbol": "WFLR", - "decimals": "18" - } - }, - "timestamp": "1734054063", - "transaction": { - "id": "0x85857b5c6d0b277f9e971b6b45cab98720f90b8f24d65df020776d675b71fc22", - "from": "0x7177b9d00bb5dbcaaf069cc63190902763783b09", - "blockNumber": "34407047", - "timestamp": "1734054063" - }, - "orderbook": { - "id": "0xcee8cd002f151a536394e564b84076c41bbbcd4d" - } - } + __typename: 'Deposit', + amount: '5000000000000000000', + newVaultBalance: '5000000000000000000', + oldVaultBalance: '0', + vault: { + id: '0x166aeed725f0f3ef9fe62f2a9054035756d55e5560b17afa1ae439e9cd362902', + vaultId: '1', + token: { + id: '0x1d80c49bbbcd1c0911346656b529df9e5c2f783d', + address: '0x1d80c49bbbcd1c0911346656b529df9e5c2f783d', + name: 'Wrapped Flare', + symbol: 'WFLR', + decimals: '18' + } + }, + timestamp: '1734054063', + transaction: { + id: '0x85857b5c6d0b277f9e971b6b45cab98720f90b8f24d65df020776d675b71fc22', + from: '0x7177b9d00bb5dbcaaf069cc63190902763783b09', + blockNumber: '34407047', + timestamp: '1734054063' + }, + orderbook: { + id: '0xcee8cd002f151a536394e564b84076c41bbbcd4d' + } + } ]; await mockServer @@ -128,16 +128,14 @@ describe('Rain Orderbook JS API Package Bindgen Vault Tests', async function () .thenReply(200, JSON.stringify({ data: { vaultBalanceChanges: mockVaultBalanceChanges } })); try { - const result: Deposit[] = await getVaultBalanceChanges( - mockServer.url + '/sg3', - vault1.id, - { page: 1, pageSize: 1 } - ); + const result: Deposit[] = await getVaultBalanceChanges(mockServer.url + '/sg3', vault1.id, { + page: 1, + pageSize: 1 + }); assert.equal(result[0].__typename, 'Deposit'); assert.equal(result[0].amount, '5000000000000000000'); assert.equal(result[0].newVaultBalance, '5000000000000000000'); assert.equal(result[0].oldVaultBalance, '0'); - } catch (e) { console.log(e); assert.fail('expected to resolve, but failed'); diff --git a/packages/ui-components/src/__tests__/FieldDefinitionButtons.test.ts b/packages/ui-components/src/__tests__/FieldDefinitionButtons.test.ts index 2b92a9a0c..13916ae15 100644 --- a/packages/ui-components/src/__tests__/FieldDefinitionButtons.test.ts +++ b/packages/ui-components/src/__tests__/FieldDefinitionButtons.test.ts @@ -2,7 +2,6 @@ import { render, fireEvent } from '@testing-library/svelte'; import { describe, it, expect, vi, beforeEach } from 'vitest'; import FieldDefinitionButtons from '../lib/components/deployment/wizard/FieldDefinitionButtons.svelte'; import { DotrainOrderGui } from '@rainlanguage/orderbook/js_api'; -import deploymentStepsStore from '../lib/components/deployment/wizard/deploymentStepsStore'; // Mock the DotrainOrderGui class vi.mock('@rainlanguage/orderbook/js_api', () => ({ @@ -27,20 +26,13 @@ describe('FieldDefinitionButtons', () => { beforeEach(() => { mockGui = new DotrainOrderGui(); - vi.spyOn(deploymentStepsStore, 'updateDeploymentStep'); }); it('renders field name and description', () => { const { getByText } = render(FieldDefinitionButtons, { props: { fieldDefinition: mockFieldDefinition, - gui: mockGui, - currentStepIndex: 0, - currentStep: { - type: 'fields', - fieldDefinition: mockFieldDefinition, - gui: mockGui - } + gui: mockGui } }); @@ -52,13 +44,7 @@ describe('FieldDefinitionButtons', () => { const { getByText } = render(FieldDefinitionButtons, { props: { fieldDefinition: mockFieldDefinition, - gui: mockGui, - currentStepIndex: 0, - currentStep: { - type: 'fields', - fieldDefinition: mockFieldDefinition, - gui: mockGui - } + gui: mockGui } }); @@ -71,13 +57,7 @@ describe('FieldDefinitionButtons', () => { const { getByText } = render(FieldDefinitionButtons, { props: { fieldDefinition: mockFieldDefinition, - gui: mockGui, - currentStepIndex: 0, - currentStep: { - type: 'fields', - fieldDefinition: mockFieldDefinition, - gui: mockGui - } + gui: mockGui } }); @@ -87,20 +67,13 @@ describe('FieldDefinitionButtons', () => { isPreset: true, value: 'preset1' }); - expect(deploymentStepsStore.updateDeploymentStep).toHaveBeenCalled(); }); it('shows custom input when Custom button is clicked', async () => { const { getByText, getByPlaceholderText } = render(FieldDefinitionButtons, { props: { fieldDefinition: mockFieldDefinition, - gui: mockGui, - currentStepIndex: 0, - currentStep: { - type: 'fields', - fieldDefinition: mockFieldDefinition, - gui: mockGui - } + gui: mockGui } }); @@ -112,13 +85,7 @@ describe('FieldDefinitionButtons', () => { const { getByText, getByPlaceholderText } = render(FieldDefinitionButtons, { props: { fieldDefinition: mockFieldDefinition, - gui: mockGui, - currentStepIndex: 0, - currentStep: { - type: 'fields', - fieldDefinition: mockFieldDefinition, - gui: mockGui - } + gui: mockGui } }); @@ -130,7 +97,6 @@ describe('FieldDefinitionButtons', () => { isPreset: false, value: 'custom value' }); - expect(deploymentStepsStore.updateDeploymentStep).toHaveBeenCalled(); }); it('does not show Custom button for is-fast-exit binding', () => { @@ -142,13 +108,7 @@ describe('FieldDefinitionButtons', () => { const { queryByText } = render(FieldDefinitionButtons, { props: { fieldDefinition: fastExitFieldDef, - gui: mockGui, - currentStepIndex: 0, - currentStep: { - type: 'fields', - fieldDefinition: fastExitFieldDef, - gui: mockGui - } + gui: mockGui } }); diff --git a/packages/ui-components/src/__tests__/TokenInput.test.ts b/packages/ui-components/src/__tests__/TokenInputOrOutput.test.ts similarity index 60% rename from packages/ui-components/src/__tests__/TokenInput.test.ts rename to packages/ui-components/src/__tests__/TokenInputOrOutput.test.ts index 8457fa66a..5076a07f1 100644 --- a/packages/ui-components/src/__tests__/TokenInput.test.ts +++ b/packages/ui-components/src/__tests__/TokenInputOrOutput.test.ts @@ -1,9 +1,9 @@ import { render, fireEvent } from '@testing-library/svelte'; import { describe, it, expect, vi, beforeEach } from 'vitest'; -import TokenInput from '../lib/components/deployment/TokenInput.svelte'; +import TokenInputOrOutput from '../lib/components/deployment/TokenInputOrOutput.svelte'; import type { ComponentProps } from 'svelte'; -export type TokenInputComponentProps = ComponentProps; +export type TokenInputOrOutputComponentProps = ComponentProps; describe('TokenInput', () => { const mockTokenInfos = new Map([ @@ -21,36 +21,37 @@ describe('TokenInput', () => { setVaultId: vi.fn() }; - const mockProps: TokenInputComponentProps = { + const mockProps: TokenInputOrOutputComponentProps = { i: 0, - input: mockInput, + label: 'Input', + vault: mockInput, tokenInfos: mockTokenInfos, - inputVaultIds: ['vault1'], + vaultIds: ['vault1'], gui: mockGui - } as unknown as TokenInputComponentProps; + } as unknown as TokenInputOrOutputComponentProps; beforeEach(() => { vi.clearAllMocks(); }); it('renders with correct label and token symbol', () => { - const { getByText } = render(TokenInput, mockProps); + const { getByText } = render(TokenInputOrOutput, mockProps); expect(getByText('Input 1 (ETH)')).toBeInTheDocument(); }); it('renders input field with correct placeholder', () => { - const { getByPlaceholderText } = render(TokenInput, mockProps); + const { getByPlaceholderText } = render(TokenInputOrOutput, mockProps); const input = getByPlaceholderText('Enter vault ID'); expect(input).toBeInTheDocument(); }); it('displays the correct vault ID value', () => { - const { getByDisplayValue } = render(TokenInput, mockProps); + const { getByDisplayValue } = render(TokenInputOrOutput, mockProps); expect(getByDisplayValue('vault1')).toBeInTheDocument(); }); it('calls setVaultId when input changes', async () => { - const { getByPlaceholderText } = render(TokenInput, mockProps); + const { getByPlaceholderText } = render(TokenInputOrOutput, mockProps); const input = getByPlaceholderText('Enter vault ID'); await fireEvent.change(input, { target: { value: 'vault1' } }); @@ -59,8 +60,11 @@ describe('TokenInput', () => { }); it('does not call setVaultId when gui is undefined', async () => { - const propsWithoutGui = { ...mockProps, gui: undefined } as unknown as TokenInputComponentProps; - const { getByPlaceholderText } = render(TokenInput, propsWithoutGui); + const propsWithoutGui = { + ...mockProps, + gui: undefined + } as unknown as TokenInputOrOutputComponentProps; + const { getByPlaceholderText } = render(TokenInputOrOutput, propsWithoutGui); const input = getByPlaceholderText('Enter vault ID'); await fireEvent.change(input, { target: { value: 'newVault' } }); @@ -71,12 +75,12 @@ describe('TokenInput', () => { it('handles missing token info gracefully', () => { const propsWithUnknownToken = { ...mockProps, - input: { token: { address: '0x789' } } + vault: { token: { address: '0x789' } } }; const { getByText } = render( - TokenInput, - propsWithUnknownToken as unknown as TokenInputComponentProps + TokenInputOrOutput, + propsWithUnknownToken as unknown as TokenInputOrOutputComponentProps ); - expect(getByText('Input 1 ()')).toBeInTheDocument(); + expect(getByText('Input 1 (Unknown)')).toBeInTheDocument(); }); }); diff --git a/packages/ui-components/src/__tests__/deploymentStepsStore.test.ts b/packages/ui-components/src/__tests__/deploymentStepsStore.test.ts deleted file mode 100644 index 7dc3844d9..000000000 --- a/packages/ui-components/src/__tests__/deploymentStepsStore.test.ts +++ /dev/null @@ -1,104 +0,0 @@ -import { get } from 'svelte/store'; -import deploymentStepsStore from '../lib/components/deployment/wizard/deploymentStepsStore'; -import type { WizardStep, TokenInputStep, FieldStep } from '../lib/types/wizardSteps'; - -describe('deploymentStepsStore', () => { - beforeEach(() => { - deploymentStepsStore.reset(); - }); - - it('should initialize with empty array', () => { - const steps = get(deploymentStepsStore); - expect(steps).toEqual([]); - }); - - it('should populate steps correctly', () => { - const mockSteps: WizardStep[] = [ - { - type: 'tokenInput', - input: { - token: '0x123...', - decimals: 18, - symbol: 'TEST' - }, - gui: { - name: 'Test GUI', - description: 'Test Description' - }, - tokenInfos: {}, - i: 0, - inputVaultIds: ['vault1', 'vault2'] - } as unknown as TokenInputStep, - { - type: 'fields', - fieldDefinition: { - name: 'Test Field', - type: 'uint256' - }, - gui: { - name: 'Test GUI', - description: 'Test Description' - } - } as unknown as FieldStep - ]; - - deploymentStepsStore.populateDeploymentSteps(mockSteps); - const steps = get(deploymentStepsStore); - - expect(steps).toEqual(mockSteps); - }); - - it('should update a specific step correctly', () => { - const initialSteps: WizardStep[] = [ - { - type: 'tokenInput', - input: { - token: '0x123...', - decimals: 18, - symbol: 'TEST' - }, - gui: { - name: 'Test GUI', - description: 'Test Description' - }, - tokenInfos: {}, - i: 0, - inputVaultIds: ['vault1'] - } as unknown as TokenInputStep - ]; - - deploymentStepsStore.populateDeploymentSteps(initialSteps); - - const updatedStep: TokenInputStep = { - ...initialSteps[0], - inputVaultIds: ['vault1', 'vault2'] - } as unknown as TokenInputStep; - - deploymentStepsStore.updateDeploymentStep(0, updatedStep); - - const steps = get(deploymentStepsStore); - expect(steps[0]).toEqual(updatedStep); - }); - - it('should reset store to initial state', () => { - const mockSteps: WizardStep[] = [ - { - type: 'fields', - fieldDefinition: { - name: 'Test Field', - type: 'uint256' - }, - gui: { - name: 'Test GUI', - description: 'Test Description' - } - } as unknown as FieldStep - ]; - - deploymentStepsStore.populateDeploymentSteps(mockSteps); - deploymentStepsStore.reset(); - - const steps = get(deploymentStepsStore); - expect(steps).toEqual([]); - }); -}); diff --git a/packages/ui-components/src/__tests__/getDeploymentSteps.test.ts b/packages/ui-components/src/__tests__/getDeploymentSteps.test.ts deleted file mode 100644 index a1d3b92ea..000000000 --- a/packages/ui-components/src/__tests__/getDeploymentSteps.test.ts +++ /dev/null @@ -1,98 +0,0 @@ -/* eslint-disable @typescript-eslint/no-explicit-any */ -import { getDeploymentSteps } from '../lib/components/deployment/wizard/getDeploymentSteps'; -import { describe, it, expect } from 'vitest'; - -describe('getDeploymentSteps', () => { - const mockGui = {} as any; - const mockTokenInfos = {} as any; - - it('should return empty array when no inputs provided', () => { - const steps = getDeploymentSteps( - new Map(), - false, - [], - mockGui, - [], - [], - [], - [], - [], - mockTokenInfos - ); - - expect(steps).toEqual([]); - }); - - it('should include select token steps for limit strategy', () => { - const selectTokens = new Map([['TOKEN1', 'address1']]); - - const steps = getDeploymentSteps( - selectTokens, - true, - [], - mockGui, - [], - [], - [], - [], - [], - mockTokenInfos - ); - - expect(steps[0]).toEqual({ - type: 'tokens', - token: 'TOKEN1', - gui: mockGui, - selectTokens - }); - }); - - it('should not include select token steps when not limit strategy', () => { - const selectTokens = new Map([['TOKEN1', 'address1']]); - - const steps = getDeploymentSteps( - selectTokens, - false, - [], - mockGui, - [], - [], - [], - [], - [], - mockTokenInfos - ); - - expect(steps).toEqual([]); - }); - - it('should include all step types in correct order', () => { - const selectTokens = new Map([['TOKEN1', 'address1']]); - const fieldDefinitions = [{ id: 'field1' }] as any; - const deposits = [{ id: 'deposit1' }] as any; - const inputs = [{ id: 'input1' }] as any; - const outputs = [{ id: 'output1' }] as any; - const inputVaultIds = ['vault1']; - const outputVaultIds = ['vault2']; - - const steps = getDeploymentSteps( - selectTokens, - true, - fieldDefinitions, - mockGui, - deposits, - inputs, - outputs, - inputVaultIds, - outputVaultIds, - mockTokenInfos - ); - - expect(steps).toHaveLength(5); - expect(steps[0].type).toBe('tokens'); - expect(steps[1].type).toBe('fields'); - expect(steps[2].type).toBe('deposits'); - expect(steps[3].type).toBe('tokenInput'); - expect(steps[4].type).toBe('tokenOutput'); - }); -}); diff --git a/packages/ui-components/src/lib/components/deployment/TokenInputOrOutput.svelte b/packages/ui-components/src/lib/components/deployment/TokenInputOrOutput.svelte index 12c0d956a..91227f162 100644 --- a/packages/ui-components/src/lib/components/deployment/TokenInputOrOutput.svelte +++ b/packages/ui-components/src/lib/components/deployment/TokenInputOrOutput.svelte @@ -13,7 +13,7 @@
{label} {i + 1} ({tokenInfos.get(vault.token.address)?.symbol || 'Unknown'})
-

{label} - {i + 1} ({tokenInfos.get(vault.token.address)?.symbol || ''}) + {i + 1} ({tokenInfos.get(vault.token.address)?.symbol || 'Unknown'})

diff --git a/packages/ui-components/src/lib/index.ts b/packages/ui-components/src/lib/index.ts index fcd2f593b..8aa5e6796 100644 --- a/packages/ui-components/src/lib/index.ts +++ b/packages/ui-components/src/lib/index.ts @@ -51,11 +51,10 @@ export { default as DepositDropdown } from './components/deployment/DepositDropd export { default as FieldDefinitionButtons } from './components/deployment/wizard/FieldDefinitionButtons.svelte'; export { default as DepositButtons } from './components/deployment/wizard/DepositButtons.svelte'; export { default as DeploymentSteps } from './components/deployment/wizard/DeploymentSteps.svelte'; -export { default as TokenInputOrOutput } from './components/deployment/TokenInputOrOutput.svelte'; export { default as TokenOutput } from './components/deployment/TokenInputOrOutput.svelte'; export { default as SelectToken } from './components/deployment/SelectToken.svelte'; -export { default as InputToken } from './components/input/InputToken.svelte'; export { default as TokenInputOrOutputWizard } from './components/deployment/wizard/TokenInputOrOutputWizard.svelte'; +export { default as TokenInputOrOutput } from './components/deployment/TokenInputOrOutput.svelte'; export { default as VaultBalanceChangesTable } from './components/tables/VaultBalanceChangesTable.svelte'; export { default as VaultBalanceChart } from './components/charts/VaultBalanceChart.svelte'; export { default as VaultDetail } from './components/detail/VaultDetail.svelte'; From abd55dbf74425a31bcdba7350e8cf3d6e8405b87 Mon Sep 17 00:00:00 2001 From: Jamie Harding Date: Fri, 3 Jan 2025 10:59:59 +0100 Subject: [PATCH 029/142] revert --- tauri-app/src/tests/pickConfig.test.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tauri-app/src/tests/pickConfig.test.ts b/tauri-app/src/tests/pickConfig.test.ts index 8cb963817..267bb71a6 100644 --- a/tauri-app/src/tests/pickConfig.test.ts +++ b/tauri-app/src/tests/pickConfig.test.ts @@ -48,6 +48,7 @@ export const config: Config = { tokens: {}, orders: { buy: { + key: 'buy', inputs: [], outputs: [], network: { @@ -57,6 +58,7 @@ export const config: Config = { }, }, sell: { + key: 'sell', inputs: [], outputs: [], network: { @@ -124,6 +126,7 @@ export const config: Config = { }, }, order: { + key: 'sell', inputs: [], outputs: [], network: { @@ -148,6 +151,7 @@ export const config: Config = { }, }, order: { + key: 'buy', inputs: [], outputs: [], network: { @@ -310,4 +314,4 @@ test('pick scenarios when empty', () => { const expectedPickedScenarios: Dictionary = {}; expect(result).toStrictEqual(expectedPickedScenarios); -}); +}); \ No newline at end of file From d86b5eb6d44372fbcdf2d86f9678c4801465b673 Mon Sep 17 00:00:00 2001 From: Jamie Harding Date: Fri, 3 Jan 2025 11:19:49 +0100 Subject: [PATCH 030/142] format --- tauri-app/src/tests/pickConfig.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tauri-app/src/tests/pickConfig.test.ts b/tauri-app/src/tests/pickConfig.test.ts index 267bb71a6..f295d21ce 100644 --- a/tauri-app/src/tests/pickConfig.test.ts +++ b/tauri-app/src/tests/pickConfig.test.ts @@ -314,4 +314,4 @@ test('pick scenarios when empty', () => { const expectedPickedScenarios: Dictionary = {}; expect(result).toStrictEqual(expectedPickedScenarios); -}); \ No newline at end of file +}); From cffef4a32544a064e755f9acfc65b02b2ff4093b Mon Sep 17 00:00:00 2001 From: Jamie Harding Date: Fri, 3 Jan 2025 16:43:29 +0100 Subject: [PATCH 031/142] remove old deploy form --- crates/js_api/src/gui/deposits.rs | 7 +- .../{wizard => }/DeploymentSteps.svelte | 8 +- .../{wizard => }/DepositButtons.svelte | 48 +--- .../deployment/DepositDropdown.svelte | 62 ----- .../FieldDefinitionButtons.svelte | 48 +--- .../deployment/FieldDefinitionDropdown.svelte | 64 ----- .../deployment/TokenInputOrOutput.svelte | 29 ++- .../wizard/TokenInputOrOutputWizard.svelte | 31 --- packages/ui-components/src/lib/index.ts | 10 +- .../webapp/src/routes/deployment/+page.svelte | 164 ++++-------- .../src/routes/deployment/new/+page.svelte | 239 ------------------ 11 files changed, 111 insertions(+), 599 deletions(-) rename packages/ui-components/src/lib/components/deployment/{wizard => }/DeploymentSteps.svelte (92%) rename packages/ui-components/src/lib/components/deployment/{wizard => }/DepositButtons.svelte (58%) delete mode 100644 packages/ui-components/src/lib/components/deployment/DepositDropdown.svelte rename packages/ui-components/src/lib/components/deployment/{wizard => }/FieldDefinitionButtons.svelte (62%) delete mode 100644 packages/ui-components/src/lib/components/deployment/FieldDefinitionDropdown.svelte delete mode 100644 packages/ui-components/src/lib/components/deployment/wizard/TokenInputOrOutputWizard.svelte delete mode 100644 packages/webapp/src/routes/deployment/new/+page.svelte diff --git a/crates/js_api/src/gui/deposits.rs b/crates/js_api/src/gui/deposits.rs index b46fa76bb..036800d43 100644 --- a/crates/js_api/src/gui/deposits.rs +++ b/crates/js_api/src/gui/deposits.rs @@ -23,10 +23,13 @@ impl DotrainOrderGui { .find(|dg| dg.token_name == *token) .ok_or(GuiError::DepositTokenNotFound(token.clone()))?; let amount: String = if value.is_preset { + let index = value + .value + .parse::() + .map_err(|_| GuiError::InvalidPreset)?; gui_deposit .presets - .iter() - .find(|preset| **preset == value.value) + .get(index) .ok_or(GuiError::InvalidPreset)? .clone() } else { diff --git a/packages/ui-components/src/lib/components/deployment/wizard/DeploymentSteps.svelte b/packages/ui-components/src/lib/components/deployment/DeploymentSteps.svelte similarity index 92% rename from packages/ui-components/src/lib/components/deployment/wizard/DeploymentSteps.svelte rename to packages/ui-components/src/lib/components/deployment/DeploymentSteps.svelte index 9422382a4..473ba595a 100644 --- a/packages/ui-components/src/lib/components/deployment/wizard/DeploymentSteps.svelte +++ b/packages/ui-components/src/lib/components/deployment/DeploymentSteps.svelte @@ -1,8 +1,8 @@ @@ -47,31 +38,20 @@ {preset} {/each} - -
- {/if} - {#if showCustomInput} -
- { - if (currentTarget instanceof HTMLInputElement) { - gui?.saveDeposit(deposit.token_name, currentTarget.value); - gui = gui; - } - }} - />
{/if} + +
+ { + if (currentTarget instanceof HTMLInputElement) { + gui?.saveDeposit(deposit.token_name, currentTarget.value); + gui = gui; + } + }} + /> +
diff --git a/packages/ui-components/src/lib/components/deployment/DepositDropdown.svelte b/packages/ui-components/src/lib/components/deployment/DepositDropdown.svelte deleted file mode 100644 index 5d04db276..000000000 --- a/packages/ui-components/src/lib/components/deployment/DepositDropdown.svelte +++ /dev/null @@ -1,62 +0,0 @@ - - -
- - - [ - preset, - { - label: preset - } - ]) - ), - ...{ custom: { label: 'Custom value' } } - }} - on:change={({ detail }) => { - gui?.saveDeposit(deposit.token_name, detail.value === 'custom' ? '' : detail.value || ''); - gui = gui; - }} - > - - {#if selectedRef === undefined} - Choose deposit amount - {:else if selectedOption?.label} - {selectedOption.label} - {:else} - {selectedRef} - {/if} - - - -
-
{option.label ? option.label : ref}
-
-
-
- - {#if gui?.isDepositPreset(deposit.token_name) === false} - { - if (currentTarget instanceof HTMLInputElement) { - gui?.saveDeposit(deposit.token_name, currentTarget.value); - } - }} - /> - {/if} -
diff --git a/packages/ui-components/src/lib/components/deployment/wizard/FieldDefinitionButtons.svelte b/packages/ui-components/src/lib/components/deployment/FieldDefinitionButtons.svelte similarity index 62% rename from packages/ui-components/src/lib/components/deployment/wizard/FieldDefinitionButtons.svelte rename to packages/ui-components/src/lib/components/deployment/FieldDefinitionButtons.svelte index 23780abc3..1564b2307 100644 --- a/packages/ui-components/src/lib/components/deployment/wizard/FieldDefinitionButtons.svelte +++ b/packages/ui-components/src/lib/components/deployment/FieldDefinitionButtons.svelte @@ -5,14 +5,12 @@ export let fieldDefinition: GuiFieldDefinition; export let gui: DotrainOrderGui; - let showCustomInput = false; function handlePresetClick(presetId: string) { gui?.saveFieldValue(fieldDefinition.binding, { isPreset: true, value: presetId }); - showCustomInput = false; gui = gui; } @@ -21,14 +19,6 @@ isPreset: false, value: value }); - } - - function handleCustomClick() { - showCustomInput = true; - gui?.saveFieldValue(fieldDefinition.binding, { - isPreset: false, - value: '' - }); gui = gui; } @@ -58,34 +48,20 @@ {preset.name || preset.value} {/each} - {#if fieldDefinition.binding !== 'is-fast-exit'} - - {/if} {/if}
{#if fieldDefinition.binding !== 'is-fast-exit'} - {#if !gui?.isFieldPreset(fieldDefinition.binding) || showCustomInput} -
- { - if (currentTarget instanceof HTMLInputElement) { - handleCustomInputChange(currentTarget.value); - } - }} - /> -
- {/if} +
+ { + if (currentTarget instanceof HTMLInputElement) { + handleCustomInputChange(currentTarget.value); + } + }} + /> +
{/if}
diff --git a/packages/ui-components/src/lib/components/deployment/FieldDefinitionDropdown.svelte b/packages/ui-components/src/lib/components/deployment/FieldDefinitionDropdown.svelte deleted file mode 100644 index aae92b7e5..000000000 --- a/packages/ui-components/src/lib/components/deployment/FieldDefinitionDropdown.svelte +++ /dev/null @@ -1,64 +0,0 @@ - - -
- - - [ - preset.id, - { - label: preset.name, - id: preset.id - } - ]) - ), - ...{ custom: { label: 'Custom value', id: '' } } - }} - on:change={({ detail }) => { - gui?.saveFieldValue(fieldDefinition.binding, { - isPreset: detail.value !== 'custom', - value: detail.value === 'custom' ? '' : detail.value || '' - }); - gui = gui; - }} - > - - {#if selectedRef === undefined} - Select a preset - {:else if selectedOption?.label} - {selectedOption.label} - {:else} - {selectedRef} - {/if} - - - -
-
{option.label ? option.label : ref}
-
-
-
- - {#if gui?.isFieldPreset(fieldDefinition.binding) === false} - { - if (currentTarget instanceof HTMLInputElement) { - gui?.saveFieldValue(fieldDefinition.binding, { - isPreset: false, - value: currentTarget.value - }); - } - }} - /> - {/if} -
diff --git a/packages/ui-components/src/lib/components/deployment/TokenInputOrOutput.svelte b/packages/ui-components/src/lib/components/deployment/TokenInputOrOutput.svelte index 91227f162..6848027d6 100644 --- a/packages/ui-components/src/lib/components/deployment/TokenInputOrOutput.svelte +++ b/packages/ui-components/src/lib/components/deployment/TokenInputOrOutput.svelte @@ -1,5 +1,5 @@ -
- - gui?.setVaultId(true, i, vaultIds[i])} - /> +
+
+

+ {label} + {i + 1} ({tokenInfos.get(vault.token.address)?.symbol || 'Unknown'}) +

+
+
+ gui?.setVaultId(true, i, vaultIds[i])} + /> +
diff --git a/packages/ui-components/src/lib/components/deployment/wizard/TokenInputOrOutputWizard.svelte b/packages/ui-components/src/lib/components/deployment/wizard/TokenInputOrOutputWizard.svelte deleted file mode 100644 index 6848027d6..000000000 --- a/packages/ui-components/src/lib/components/deployment/wizard/TokenInputOrOutputWizard.svelte +++ /dev/null @@ -1,31 +0,0 @@ - - -
-
-

- {label} - {i + 1} ({tokenInfos.get(vault.token.address)?.symbol || 'Unknown'}) -

-
-
- gui?.setVaultId(true, i, vaultIds[i])} - /> -
-
diff --git a/packages/ui-components/src/lib/index.ts b/packages/ui-components/src/lib/index.ts index 8aa5e6796..f9fdd436b 100644 --- a/packages/ui-components/src/lib/index.ts +++ b/packages/ui-components/src/lib/index.ts @@ -46,14 +46,12 @@ export { default as IconSuccess } from './components/IconSuccess.svelte'; export { default as IconTelegram } from './components/IconTelegram.svelte'; export { default as IconWalletConnect } from './components/IconWalletConnect.svelte'; export { default as IconWarning } from './components/IconWarning.svelte'; -export { default as FieldDefinitionDropdown } from './components/deployment/FieldDefinitionDropdown.svelte'; -export { default as DepositDropdown } from './components/deployment/DepositDropdown.svelte'; -export { default as FieldDefinitionButtons } from './components/deployment/wizard/FieldDefinitionButtons.svelte'; -export { default as DepositButtons } from './components/deployment/wizard/DepositButtons.svelte'; -export { default as DeploymentSteps } from './components/deployment/wizard/DeploymentSteps.svelte'; +export { default as FieldDefinitionButtons } from './components/deployment/FieldDefinitionButtons.svelte'; +export { default as DepositButtons } from './components/deployment/DepositButtons.svelte'; +export { default as DeploymentSteps } from './components/deployment/DeploymentSteps.svelte'; export { default as TokenOutput } from './components/deployment/TokenInputOrOutput.svelte'; export { default as SelectToken } from './components/deployment/SelectToken.svelte'; -export { default as TokenInputOrOutputWizard } from './components/deployment/wizard/TokenInputOrOutputWizard.svelte'; + export { default as TokenInputOrOutput } from './components/deployment/TokenInputOrOutput.svelte'; export { default as VaultBalanceChangesTable } from './components/tables/VaultBalanceChangesTable.svelte'; export { default as VaultBalanceChart } from './components/charts/VaultBalanceChart.svelte'; diff --git a/packages/webapp/src/routes/deployment/+page.svelte b/packages/webapp/src/routes/deployment/+page.svelte index f91bfac32..ff41fa0e5 100644 --- a/packages/webapp/src/routes/deployment/+page.svelte +++ b/packages/webapp/src/routes/deployment/+page.svelte @@ -1,12 +1,5 @@ -
- { - gui = undefined; - }} - /> -
- -
- - - - {#if selectedRef === undefined} - Select a deployment - {:else if selectedOption?.label} - {selectedOption.label} - {:else} - {selectedRef} - {/if} - - - -
-
{option.label ? option.label : ref}
-
-
-
-
- -{#if gui} - {#if isLimitStrat && selectTokens.size > 0} - - - {#each selectTokens.entries() as [token]} - - {/each} - {/if} - - {#if allFieldDefinitions.length > 0} - - {#each allFieldDefinitions as fieldDefinition} - - {/each} - {/if} - - {#if allDeposits.length > 0} - - {#each allDeposits as deposit} - - {/each} - {/if} - - {#if selectedDeployment} -
-
- -
- - {#if useCustomVaultIds} - - - {#if allTokenInputs.length > 0} - - {#each allTokenInputs as input, i} - - {/each} +
+
+ { + gui = undefined; + }} + /> +
+ +
+ + + + {#if selectedRef === undefined} + Select a deployment + {:else if selectedOption?.label} + {selectedOption.label} + {:else} + {selectedRef} {/if} - - {#if allTokenOutputs.length > 0} - - {#each allTokenOutputs as output, i} - - {/each} - {/if} - {/if} -
- - - {/if} -{/if} + + + +
+
{option.label ? option.label : ref}
+
+
+ +
+ +
+ {#if gui} + + {/if} +
+
diff --git a/packages/webapp/src/routes/deployment/new/+page.svelte b/packages/webapp/src/routes/deployment/new/+page.svelte deleted file mode 100644 index ff41fa0e5..000000000 --- a/packages/webapp/src/routes/deployment/new/+page.svelte +++ /dev/null @@ -1,239 +0,0 @@ - - -
-
- { - gui = undefined; - }} - /> -
- -
- - - - {#if selectedRef === undefined} - Select a deployment - {:else if selectedOption?.label} - {selectedOption.label} - {:else} - {selectedRef} - {/if} - - - -
-
{option.label ? option.label : ref}
-
-
-
-
- -
- {#if gui} - - {/if} -
-
From e9b229a84221b5a48c4bdb11925bfee81a0918ea Mon Sep 17 00:00:00 2001 From: Jamie Harding Date: Sat, 4 Jan 2025 14:44:03 +0100 Subject: [PATCH 032/142] fix tests --- .../src/__tests__/DepositButtons.test.ts | 17 +--- .../src/__tests__/DepositDropdown.test.ts | 95 ------------------- .../__tests__/FIeldDefinitionDropdown.test.ts | 88 ----------------- .../__tests__/FieldDefinitionButtons.test.ts | 19 +--- 4 files changed, 3 insertions(+), 216 deletions(-) delete mode 100644 packages/ui-components/src/__tests__/DepositDropdown.test.ts delete mode 100644 packages/ui-components/src/__tests__/FIeldDefinitionDropdown.test.ts diff --git a/packages/ui-components/src/__tests__/DepositButtons.test.ts b/packages/ui-components/src/__tests__/DepositButtons.test.ts index da6a4196b..532a136c2 100644 --- a/packages/ui-components/src/__tests__/DepositButtons.test.ts +++ b/packages/ui-components/src/__tests__/DepositButtons.test.ts @@ -1,6 +1,6 @@ import { describe, it, expect, vi, beforeEach } from 'vitest'; import { render, fireEvent } from '@testing-library/svelte'; -import DepositButtons from '../lib/components/deployment/wizard/DepositButtons.svelte'; +import DepositButtons from '../lib/components/deployment/DepositButtons.svelte'; import type { GuiDeposit } from '@rainlanguage/orderbook/js_api'; import type { ComponentProps } from 'svelte'; @@ -37,7 +37,6 @@ describe('DepositButtons', () => { expect(getByText('100')).toBeTruthy(); expect(getByText('200')).toBeTruthy(); expect(getByText('300')).toBeTruthy(); - expect(getByText('Custom')).toBeTruthy(); }); it('handles preset button clicks', async () => { @@ -53,20 +52,6 @@ describe('DepositButtons', () => { expect(mockGui.saveDeposit).toHaveBeenCalledWith('TEST', '100'); }); - it('shows custom input when Custom button is clicked', async () => { - const { getByText, getByPlaceholderText } = render(DepositButtons, { - props: { - deposit: mockDeposit, - gui: mockGui, - tokenInfos: mockTokenInfos - } as unknown as DepositButtonsProps - }); - - await fireEvent.click(getByText('Custom')); - expect(getByPlaceholderText('Enter deposit amount')).toBeTruthy(); - expect(mockGui.saveDeposit).toHaveBeenCalledWith('TEST', ''); - }); - it('handles custom input changes', async () => { mockGui.isDepositPreset.mockReturnValue(false); diff --git a/packages/ui-components/src/__tests__/DepositDropdown.test.ts b/packages/ui-components/src/__tests__/DepositDropdown.test.ts deleted file mode 100644 index 960e27e15..000000000 --- a/packages/ui-components/src/__tests__/DepositDropdown.test.ts +++ /dev/null @@ -1,95 +0,0 @@ -import { describe, it, expect, vi } from 'vitest'; -import { render, fireEvent } from '@testing-library/svelte'; -import DepositDropdown from '../lib/components/deployment/DepositDropdown.svelte'; -import type { DotrainOrderGui, GuiDeposit } from '@rainlanguage/orderbook/js_api'; - -describe('DepositDropdown', () => { - const mockTokenInfos = new Map(); - mockTokenInfos.set('0x123', { name: 'Test Token' }); - - const mockDeposit: GuiDeposit = { - token: { address: '0x123' }, - token_name: 'TEST', - presets: ['100', '200', '300'] - } as unknown as GuiDeposit; - - const mockGui = { - saveDeposit: vi.fn(), - isDepositPreset: vi.fn() - }; - - it('renders token name correctly', () => { - const { getByText } = render(DepositDropdown, { - props: { - deposit: mockDeposit, - gui: mockGui as unknown as DotrainOrderGui, - tokenInfos: mockTokenInfos - } - }); - - expect(getByText('Test Token')).toBeTruthy(); - }); - - it('shows "Choose deposit amount" by default', () => { - const { getByText } = render(DepositDropdown, { - props: { - deposit: mockDeposit, - gui: mockGui as unknown as DotrainOrderGui, - tokenInfos: mockTokenInfos - } - }); - - expect(getByText('Choose deposit amount')).toBeTruthy(); - }); - - it('calls saveDeposit when preset is selected', async () => { - mockGui.isDepositPreset.mockReturnValue(true); - - const { getByText } = render(DepositDropdown, { - props: { - deposit: mockDeposit, - gui: mockGui as unknown as DotrainOrderGui, - tokenInfos: mockTokenInfos - } - }); - - await fireEvent.click(getByText('Choose deposit amount')); - await fireEvent.click(getByText('100')); - - expect(mockGui.saveDeposit).toHaveBeenCalledWith('TEST', '100'); - }); - - it('shows input field when custom value is selected', async () => { - mockGui.isDepositPreset.mockReturnValue(false); - - const { getByText, getByPlaceholderText } = render(DepositDropdown, { - props: { - deposit: mockDeposit, - gui: mockGui as unknown as DotrainOrderGui, - tokenInfos: mockTokenInfos - } - }); - - await fireEvent.click(getByText('Choose deposit amount')); - await fireEvent.click(getByText('Custom value')); - - expect(getByPlaceholderText('Enter deposit amount')).toBeTruthy(); - }); - - it('calls saveDeposit when custom value is entered', async () => { - mockGui.isDepositPreset.mockReturnValue(false); - - const { getByPlaceholderText } = render(DepositDropdown, { - props: { - deposit: mockDeposit, - gui: mockGui as unknown as DotrainOrderGui, - tokenInfos: mockTokenInfos - } - }); - - const input = getByPlaceholderText('Enter deposit amount'); - await fireEvent.change(input, { target: { value: '150' } }); - - expect(mockGui.saveDeposit).toHaveBeenCalledWith('TEST', '150'); - }); -}); diff --git a/packages/ui-components/src/__tests__/FIeldDefinitionDropdown.test.ts b/packages/ui-components/src/__tests__/FIeldDefinitionDropdown.test.ts deleted file mode 100644 index 099c9020b..000000000 --- a/packages/ui-components/src/__tests__/FIeldDefinitionDropdown.test.ts +++ /dev/null @@ -1,88 +0,0 @@ -import { describe, it, expect, vi, beforeEach, type Mock } from 'vitest'; -import { render, fireEvent, screen } from '@testing-library/svelte'; -import FieldDefinitionDropdown from '../lib/components/deployment/FieldDefinitionDropdown.svelte'; -import type { DotrainOrderGui, GuiFieldDefinition } from '@rainlanguage/orderbook/js_api'; -import type { ComponentProps } from 'svelte'; - -export type FieldDefinitionDropdownProps = ComponentProps; - -describe('FieldDefinitionDropdown', () => { - let mockGui: DotrainOrderGui; - let fieldDefinition: GuiFieldDefinition; - - beforeEach(() => { - mockGui = { - saveFieldValue: vi.fn(), - isFieldPreset: vi.fn() - } as unknown as DotrainOrderGui; - - fieldDefinition = { - name: 'Test Field', - binding: 'test-binding', - presets: [ - { id: 'preset1', name: 'Preset 1', value: '' }, - { id: 'preset2', name: 'Preset 2', value: '' } - ] - } as unknown as GuiFieldDefinition; - }); - - it('renders field name correctly', () => { - render(FieldDefinitionDropdown, { props: { fieldDefinition, gui: mockGui } }); - expect(screen.getByText('Test Field')).toBeInTheDocument(); - }); - - it('shows presets in dropdown', async () => { - render(FieldDefinitionDropdown, { props: { fieldDefinition, gui: mockGui } }); - - // Open dropdown - const dropdown = screen.getByText('Select a preset'); - await fireEvent.click(dropdown); - - // Check if presets are rendered - expect(screen.getByText('Preset 1')).toBeInTheDocument(); - expect(screen.getByText('Preset 2')).toBeInTheDocument(); - expect(screen.getByText('Custom value')).toBeInTheDocument(); - }); - - it('calls saveFieldValue when preset is selected', async () => { - render(FieldDefinitionDropdown, { props: { fieldDefinition, gui: mockGui } }); - - // Open dropdown and select preset - const dropdown = screen.getByText('Select a preset'); - await fireEvent.click(dropdown); - await fireEvent.click(screen.getByText('Preset 1')); - - expect(mockGui.saveFieldValue).toHaveBeenCalledWith('test-binding', { - isPreset: true, - value: 'preset1' - }); - }); - - it('shows input field when custom value is selected', async () => { - (mockGui.isFieldPreset as Mock).mockReturnValue(false); - - render(FieldDefinitionDropdown, { props: { fieldDefinition, gui: mockGui } }); - - // Open dropdown and select custom - const dropdown = screen.getByText('Select a preset'); - await fireEvent.click(dropdown); - await fireEvent.click(screen.getByText('Custom value')); - - // Check if input field appears - const input = screen.getByPlaceholderText('Enter value'); - expect(input).toBeInTheDocument(); - - // Test input change - await fireEvent.change(input, { target: { value: 'custom input' } }); - expect(mockGui.saveFieldValue).toHaveBeenCalledWith('test-binding', { - isPreset: false, - value: 'custom input' - }); - }); - - it('handles case when gui is not provided', () => { - render(FieldDefinitionDropdown, { props: { fieldDefinition } as FieldDefinitionDropdownProps }); - expect(screen.getByText('Test Field')).toBeInTheDocument(); - // Should not throw any errors - }); -}); diff --git a/packages/ui-components/src/__tests__/FieldDefinitionButtons.test.ts b/packages/ui-components/src/__tests__/FieldDefinitionButtons.test.ts index 13916ae15..2bd8d70f3 100644 --- a/packages/ui-components/src/__tests__/FieldDefinitionButtons.test.ts +++ b/packages/ui-components/src/__tests__/FieldDefinitionButtons.test.ts @@ -1,9 +1,8 @@ import { render, fireEvent } from '@testing-library/svelte'; import { describe, it, expect, vi, beforeEach } from 'vitest'; -import FieldDefinitionButtons from '../lib/components/deployment/wizard/FieldDefinitionButtons.svelte'; +import FieldDefinitionButtons from '../lib/components/deployment/FieldDefinitionButtons.svelte'; import { DotrainOrderGui } from '@rainlanguage/orderbook/js_api'; -// Mock the DotrainOrderGui class vi.mock('@rainlanguage/orderbook/js_api', () => ({ DotrainOrderGui: vi.fn().mockImplementation(() => ({ saveFieldValue: vi.fn(), @@ -50,7 +49,6 @@ describe('FieldDefinitionButtons', () => { expect(getByText('Preset 1')).toBeTruthy(); expect(getByText('Preset 2')).toBeTruthy(); - expect(getByText('Custom')).toBeTruthy(); }); it('handles preset button clicks', async () => { @@ -69,27 +67,14 @@ describe('FieldDefinitionButtons', () => { }); }); - it('shows custom input when Custom button is clicked', async () => { - const { getByText, getByPlaceholderText } = render(FieldDefinitionButtons, { - props: { - fieldDefinition: mockFieldDefinition, - gui: mockGui - } - }); - - await fireEvent.click(getByText('Custom')); - expect(getByPlaceholderText('Enter custom value')).toBeTruthy(); - }); - it('handles custom input changes', async () => { - const { getByText, getByPlaceholderText } = render(FieldDefinitionButtons, { + const { getByPlaceholderText } = render(FieldDefinitionButtons, { props: { fieldDefinition: mockFieldDefinition, gui: mockGui } }); - await fireEvent.click(getByText('Custom')); const input = getByPlaceholderText('Enter custom value'); await fireEvent.input(input, { target: { value: 'custom value' } }); From ccce590c576955bab9ce45c89e3bea2eb441e723 Mon Sep 17 00:00:00 2001 From: Jamie Harding Date: Sat, 4 Jan 2025 16:21:06 +0100 Subject: [PATCH 033/142] change prop --- .../src/lib/components/deployment/DepositButtons.svelte | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/ui-components/src/lib/components/deployment/DepositButtons.svelte b/packages/ui-components/src/lib/components/deployment/DepositButtons.svelte index 62d6b519c..786cd8681 100644 --- a/packages/ui-components/src/lib/components/deployment/DepositButtons.svelte +++ b/packages/ui-components/src/lib/components/deployment/DepositButtons.svelte @@ -11,7 +11,7 @@ export let tokenInfos: TokenInfos; function handlePresetClick(preset: string) { - gui?.saveDeposit(deposit.token_name, preset); + gui?.saveDeposit(deposit.token.key, preset); gui = gui; } @@ -30,7 +30,7 @@
-
From a47b391089cf70d3e52c84bc11036059a56c5d5a Mon Sep 17 00:00:00 2001 From: Jamie Harding Date: Sun, 5 Jan 2025 14:34:12 +0100 Subject: [PATCH 035/142] add --- .../webapp/src/routes/deployment/+page.svelte | 10 +- .../src/routes/deployment/test-strategy.md | 1266 +++++++++++++++++ 2 files changed, 1268 insertions(+), 8 deletions(-) create mode 100644 packages/webapp/src/routes/deployment/test-strategy.md diff --git a/packages/webapp/src/routes/deployment/+page.svelte b/packages/webapp/src/routes/deployment/+page.svelte index 5a4648968..a0be2d756 100644 --- a/packages/webapp/src/routes/deployment/+page.svelte +++ b/packages/webapp/src/routes/deployment/+page.svelte @@ -14,6 +14,7 @@ import { Button, Input, Label } from 'flowbite-svelte'; import { createWalletClient, custom, type Chain } from 'viem'; import { base, flare, arbitrum, polygon, bsc, mainnet, linea } from 'viem/chains'; + import testStrategy from './test-strategy.md?raw'; const chains: Record = { [base.id]: base, @@ -25,18 +26,11 @@ [linea.id]: linea }; - let strategyUrl = - 'https://raw.githubusercontent.com/rainlanguage/rain.webapp/refs/heads/main/public/_strategies/raindex/2-dynamic-spread/dynamic-spread.rain'; - let dotrain = ''; let isLimitStrat = false; async function loadStrategy() { - const response = await fetch(strategyUrl); - if (!response.ok) { - throw new Error('Failed to load strategy'); - } - dotrain = await response.text(); + dotrain = testStrategy; } let gui: DotrainOrderGui | undefined = undefined; diff --git a/packages/webapp/src/routes/deployment/test-strategy.md b/packages/webapp/src/routes/deployment/test-strategy.md new file mode 100644 index 000000000..6c1488141 --- /dev/null +++ b/packages/webapp/src/routes/deployment/test-strategy.md @@ -0,0 +1,1266 @@ + +raindex-version: 8898591f3bcaa21dc91dc3b8584330fc405eadfa + +gui: + name: Two-sided dynamic spread strategies + description: The dynamic spread strategy for market-making uses time-based adjustments to maintain liquidity by narrowing spreads as market conditions stabilize, while recalculating averages and trade sizes to mitigate risks during trends. + deployments: + flare-sflr-wflr: + name: SFLR<>WFLR on Flare. + description: Rotate sFLR (Sceptre staked FLR) and WFLR on Flare. + fields: + - binding: is-fast-exit + name: Fast exit? + description: If enabled, the strategy will attempt to exit any position it builds up in a single trade, as soon as it can do so profitably. + presets: + - name: Yes + value: 1 + - name: No + value: 0 + - binding: initial-io + name: Initial price (WFLR per sFLR) + description: The rough initial WFLR to sFLR ratio (e.g. 1.11). + min: 1 + - binding: next-trade-multiplier + name: Next trade multiplier + description: This is the most the strategy will move the price in a single trade. Larger numbers will capture larger price jumps but trade less often, smaller numbers will trade more often but be less defensive against large price jumps in the market. + min: 1 + presets: + - name: 1.001x + value: 1.001 + - name: 1.002x + value: 1.002 + - name: 1.005x + value: 1.005 + - binding: cost-basis-multiplier + name: Cost basis multiplier + description: The minimum spread applied to the breakeven in addition to the auction. This is applied in both directions so 1.01x would be a 2% total spread. + min: 1 + presets: + - name: 1 (auction spread only) + value: 1 + - name: 1.0005x (0.1% total) + value: 1.0005 + - name: 1.001x (0.2% total) + value: 1.001 + - name: 1.0025x (0.5% total) + value: 1.0025 + - name: 1.005x (1% total) + value: 1.005 + - binding: time-per-epoch + name: Time per halving (seconds) + description: The amount of time (in seconds) between halvings of the price and the amount offered during each auction, relative to their baselines. + min: 600 + presets: + - name: 1 hour (3600) + value: 3600 + - name: 2 hours (7200) + value: 7200 + - name: 4 hours (14400) + value: 14400 + - name: 8 hours (28800) + value: 28800 + - binding: max-amount + name: Max amount + description: The maximum amount of sFLR that will be offered in a single auction. + min: 0 + presets: + - name: 100 + value: 100 + - name: 1000 + value: 1000 + - name: 10000 + value: 10000 + - name: 100000 + value: 100000 + - binding: min-amount + name: Minimum amount + description: The minimum amount of sFLR that will be offered in a single auction. + min: 0 + presets: + - name: 10 + value: 10 + - name: 100 + value: 100 + - name: 1000 + value: 1000 + + deposits: + - token: flare-sflr + min: 0 + presets: + - 0 + - 100 + - 1000 + - 10000 + - token: flare-wflr + min: 0 + presets: + - 0 + - 100 + - 1000 + - 10000 + flare-cusdx-cysflr: + name: cUSDX<>cysFLR on Flare. + description: Rotate cUSDX and cysFLR on Flare. + + fields: + - binding: is-fast-exit + name: Fast exit? + description: If enabled, the strategy will attempt to exit any position it builds up in a single trade, as soon as it can do so profitably. + presets: + - name: Yes + value: 1 + - name: No + value: 0 + - binding: initial-io + name: Initial price (cUSDX per cysFLR) + description: The rough initial cUSDX per cysFLR ratio (e.g. 0.75). + min: 0 + - binding: next-trade-multiplier + name: Next trade multiplier + description: This is the most the strategy will move the price in a single trade. Larger numbers will capture larger price jumps but trade less often, smaller numbers will trade more often but be less defensive against large price jumps in the market. + min: 1 + presets: + - name: 1.001x + value: 1.001 + - name: 1.002x + value: 1.002 + - name: 1.005x + value: 1.005 + - binding: cost-basis-multiplier + name: Cost basis multiplier + description: The minimum spread applied to the breakeven in addition to the auction. This is applied in both directions so 1.01x would be a 2% total spread. + min: 1 + presets: + - name: 1 (auction spread only) + value: 1 + - name: 1.0005x (0.1% total) + value: 1.0005 + - name: 1.001x (0.2% total) + value: 1.001 + - name: 1.0025x (0.5% total) + value: 1.0025 + - name: 1.005x (1% total) + value: 1.005 + - binding: time-per-epoch + name: Time per halving (seconds) + description: The amount of time (in seconds) between halvings of the price and the amount offered during each auction, relative to their baselines. + min: 600 + presets: + - name: 1 hour (3600) + value: 3600 + - name: 2 hours (7200) + value: 7200 + - name: 4 hours (14400) + value: 14400 + - name: 8 hours (28800) + value: 28800 + - binding: max-amount + name: Max amount + description: The maximum amount of cUSDX that will be offered in a single auction. + min: 0 + presets: + - name: 10 + value: 10 + - name: 100 + value: 100 + - name: 1000 + value: 1000 + - binding: min-amount + name: Minimum amount + description: The minimum amount of cUSDX that will be offered in a single auction. + min: 0 + presets: + - name: 10 + value: 10 + - name: 100 + value: 100 + - name: 1000 + value: 1000 + + deposits: + - token: flare-cysflr + min: 0 + presets: + - 0 + - 100 + - 200 + - 500 + - token: flare-cusdx + min: 0 + presets: + - 0 + - 100 + - 200 + - 500 +scenarios: + arbitrum: + orderbook: arbitrum + runs: 1 + bindings: + raindex-subparser: 0xb06202aA3Fe7d85171fB7aA5f17011d17E63f382 + history-cap: '1e50' + shy-epoch: 0.05 + scenarios: + wbtc-weth: + runs: 1 + bindings: + amount-token: 0x2f2a2543B76A4166549F7aaB2e75Bef0aefC5B0f + initial-output-token: 0x82aF49447D8a07e3bd95BD0d56f35241523fBab1 + initial-input-token: 0x2f2a2543B76A4166549F7aaB2e75Bef0aefC5B0f + usdc-weth: + runs: 1 + bindings: + amount-token: 0xaf88d065e77c8cC2239327C5EDb3A432268e5831 + initial-output-token: 0x82aF49447D8a07e3bd95BD0d56f35241523fBab1 + initial-input-token: 0xaf88d065e77c8cC2239327C5EDb3A432268e5831 + weth-umja: + runs: 1 + bindings: + amount-token: 0x82aF49447D8a07e3bd95BD0d56f35241523fBab1 + initial-output-token: 0x16A500Aec6c37F84447ef04E66c57cfC6254cF92 + initial-input-token: 0x82aF49447D8a07e3bd95BD0d56f35241523fBab1 + usdt-kima: + runs: 1 + bindings: + amount-token: 0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9 + initial-output-token: 0x94fCD9c18f99538C0f7C61c5500cA79F0D5C4dab + initial-input-token: 0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9 + glo-lusd: + runs: 1 + bindings: + amount-token: 0x4F604735c1cF31399C6E711D5962b2B3E0225AD3 + initial-output-token: 0x93b346b6BC2548dA6A1E7d98E9a421B42541425b + initial-input-token: 0x4F604735c1cF31399C6E711D5962b2B3E0225AD3 + base: + orderbook: base + runs: 1 + bindings: + raindex-subparser: 0x662dFd6d5B6DF94E07A60954901D3001c24F856a + history-cap: '1e50' + shy-epoch: 0.05 + scenarios: + usdc-weth: + runs: 1 + bindings: + amount-token: 0x833589fcd6edb6e08f4c7c32d4f71b54bda02913 + initial-output-token: 0x4200000000000000000000000000000000000006 + initial-input-token: 0x833589fcd6edb6e08f4c7c32d4f71b54bda02913 + lucky-weth: + runs: 1 + bindings: + amount-token: 0x2C002ffEC41568d138Acc36f5894d6156398D539 + initial-output-token: 0x2C002ffEC41568d138Acc36f5894d6156398D539 + initial-input-token: 0x4200000000000000000000000000000000000006 + usdc-toshi: + runs: 1 + bindings: + amount-token: 0x833589fcd6edb6e08f4c7c32d4f71b54bda02913 + initial-output-token: 0xac1bd2486aaf3b5c0fc3fd868558b082a531b2b4 + initial-input-token: 0x833589fcd6edb6e08f4c7c32d4f71b54bda02913 + usdc-paid: + runs: 1 + bindings: + amount-token: 0x833589fcd6edb6e08f4c7c32d4f71b54bda02913 + initial-output-token: 0x655A51e6803faF50D4acE80fa501af2F29C856cF + initial-input-token: 0x833589fcd6edb6e08f4c7c32d4f71b54bda02913 + wlth-usdc: + runs: 1 + bindings: + amount-token: 0x833589fcd6edb6e08f4c7c32d4f71b54bda02913 + initial-output-token: 0x99b2B1A2aDB02B38222ADcD057783D7e5D1FCC7D + initial-input-token: 0x833589fcd6edb6e08f4c7c32d4f71b54bda02913 + usdc-blood: + runs: 1 + bindings: + amount-token: 0x833589fcd6edb6e08f4c7c32d4f71b54bda02913 + initial-output-token: 0x3982E57fF1b193Ca8eb03D16Db268Bd4B40818f8 + initial-input-token: 0x833589fcd6edb6e08f4c7c32d4f71b54bda02913 + + flare: + orderbook: flare + runs: 1 + bindings: + raindex-subparser: 0xFe2411CDa193D9E4e83A5c234C7Fd320101883aC + history-cap: '1e50' + shy-epoch: 0.05 + scenarios: + sflr-wflr: + runs: 1 + bindings: + amount-token: 0x12e605bc104e93B45e1aD99F9e555f659051c2BB + initial-output-token: 0x12e605bc104e93B45e1aD99F9e555f659051c2BB + initial-input-token: 0x1D80c49BbBCd1C0911346656B529DF9E5c2F783d + cusdx-cysflr: + runs: 1 + bindings: + amount-token: 0xFE2907DFa8DB6e320cDbF45f0aa888F6135ec4f8 + initial-output-token: 0x19831cfB53A0dbeAD9866C43557C1D48DfF76567 + initial-input-token: 0xFE2907DFa8DB6e320cDbF45f0aa888F6135ec4f8 + sflr-joule: + runs: 1 + bindings: + amount-token: 0x12e605bc104e93B45e1aD99F9e555f659051c2BB + initial-output-token: 0xE6505f92583103AF7ed9974DEC451A7Af4e3A3bE + initial-input-token: 0x12e605bc104e93B45e1aD99F9e555f659051c2BB + wflr-eusdt: + runs: 1 + bindings: + amount-token: 0xfbda5f676cb37624f28265a144a48b0d6e87d3b6 + initial-output-token: 0x12e605bc104e93B45e1aD99F9e555f659051c2BB + initial-input-token: 0xfbda5f676cb37624f28265a144a48b0d6e87d3b6 + usdce-sflr: + runs: 1 + bindings: + amount-token: 0xfbda5f676cb37624f28265a144a48b0d6e87d3b6 + initial-output-token: 0x12e605bc104e93B45e1aD99F9e555f659051c2BB + initial-input-token: 0xfbda5f676cb37624f28265a144a48b0d6e87d3b6 + usdce-cusdx: + runs: 1 + bindings: + amount-token: 0xfbda5f676cb37624f28265a144a48b0d6e87d3b6 + initial-output-token: 0xFE2907DFa8DB6e320cDbF45f0aa888F6135ec4f8 + initial-input-token: 0xfbda5f676cb37624f28265a144a48b0d6e87d3b6 + usdce-wflr: + runs: 1 + bindings: + amount-token: 0xfbda5f676cb37624f28265a144a48b0d6e87d3b6 + initial-output-token: 0x1D80c49BbBCd1C0911346656B529DF9E5c2F783d + initial-input-token: 0xfbda5f676cb37624f28265a144a48b0d6e87d3b6 + usdce-weth: + runs: 1 + bindings: + amount-token: 0xfbda5f676cb37624f28265a144a48b0d6e87d3b6 + initial-output-token: 0x1502FA4be69d526124D453619276FacCab275d3D + initial-input-token: 0xfbda5f676cb37624f28265a144a48b0d6e87d3b6 + polygon: + orderbook: polygon + runs: 1 + bindings: + raindex-subparser: 0xF9323B7d23c655122Fb0272D989b83E105cBcf9d + history-cap: '1e50' + shy-epoch: 0.05 + scenarios: + quick-old-quick: + runs: 1 + bindings: + amount-token: 0xB5C064F955D8e7F38fE0460C556a72987494eE17 + initial-output-token: 0x831753dd7087cac61ab5644b308642cc1c33dc13 + initial-input-token: 0xB5C064F955D8e7F38fE0460C556a72987494eE17 + quick-wmatic: + runs: 1 + bindings: + amount-token: 0x0d500B1d8E8eF31E21C99d1Db9A6444d3ADf1270 + initial-output-token: 0xB5C064F955D8e7F38fE0460C556a72987494eE17 + initial-input-token: 0x0d500B1d8E8eF31E21C99d1Db9A6444d3ADf1270 + usdc-ioen: + runs: 1 + bindings: + amount-token: 0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359 + initial-output-token: 0xd0e9c8f5Fae381459cf07Ec506C1d2896E8b5df6 + initial-input-token: 0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359 + usdc-mnw: + runs: 1 + bindings: + amount-token: 0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359 + initial-output-token: 0x3c59798620e5fEC0Ae6dF1A19c6454094572Ab92 + initial-input-token: 0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359 + usdt-poli: + runs: 1 + bindings: + amount-token: 0xc2132D05D31c914a87C6611C10748AEb04B58e8F + initial-output-token: 0x6fb54Ffe60386aC33b722be13d2549dd87BF63AF + initial-input-token: 0xc2132D05D31c914a87C6611C10748AEb04B58e8F + weth-mnw: + runs: 1 + bindings: + amount-token: 0x7ceB23fD6bC0adD59E62ac25578270cFf1b9f619 + initial-output-token: 0x3c59798620e5fEC0Ae6dF1A19c6454094572Ab92 + initial-input-token: 0x7ceB23fD6bC0adD59E62ac25578270cFf1b9f619 + usdt-nht: + runs: 1 + bindings: + amount-token: 0xc2132D05D31c914a87C6611C10748AEb04B58e8F + initial-output-token: 0x84342e932797FC62814189f01F0Fb05F52519708 + initial-input-token: 0xc2132D05D31c914a87C6611C10748AEb04B58e8F + usdce-gfi: + runs: 1 + bindings: + amount-token: 0x2791bca1f2de4661ed88a30c99a7a9449aa84174 + initial-output-token: 0x874e178a2f3f3f9d34db862453cd756e7eab0381 + initial-input-token: 0x2791bca1f2de4661ed88a30c99a7a9449aa84174 + bsc: + orderbook: bsc + runs: 1 + bindings: + raindex-subparser: 0x662dFd6d5B6DF94E07A60954901D3001c24F856a + history-cap: '1e50' + shy-epoch: 0.05 + scenarios: + tft-busd: + runs: 1 + bindings: + amount-token: 0xe9e7CEA3DedcA5984780Bafc599bD69ADd087D56 + initial-output-token: 0x8f0FB159380176D324542b3a7933F0C2Fd0c2bbf + initial-input-token: 0xe9e7CEA3DedcA5984780Bafc599bD69ADd087D56 + tft-usdc: + runs: 1 + bindings: + amount-token: 0x8AC76a51cc950d9822D68b83fE1Ad97B32Cd580d + initial-output-token: 0x8f0FB159380176D324542b3a7933F0C2Fd0c2bbf + initial-input-token: 0x8AC76a51cc950d9822D68b83fE1Ad97B32Cd580d + ethereum: + orderbook: ethereum + runs: 1 + bindings: + raindex-subparser: 0x22410e2a46261a1B1e3899a072f303022801C764 + history-cap: '1e50' + shy-epoch: 0.05 + scenarios: + pai-weth: + runs: 1 + bindings: + amount-token: 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2 + initial-output-token: 0x13E4b8CfFe704d3De6F19E52b201d92c21EC18bD + initial-input-token: 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2 + mnw-weth: + runs: 1 + bindings: + amount-token: 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2 + initial-output-token: 0xd3E4Ba569045546D09CF021ECC5dFe42b1d7f6E4 + initial-input-token: 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2 + linea: + orderbook: linea + runs: 1 + bindings: + raindex-subparser: 0xF77b3c3f61af5a3cE7f7CE3cfFc117491104432E + history-cap: '1e50' + shy-epoch: 0.05 + scenarios: + clip-weth: + runs: 1 + bindings: + amount-token: 0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f + initial-output-token: 0x4Ea77a86d6E70FfE8Bb947FC86D68a7F086f198a + initial-input-token: 0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f + +networks: + flare: + rpc: https://rpc.ankr.com/flare + chain-id: 14 + network-id: 14 + currency: FLR + base: + rpc: https://mainnet.base.org + chain-id: 8453 + network-id: 8453 + currency: ETH + arbitrum: + rpc: https://rpc.ankr.com/arbitrum + chain-id: 42161 + network-id: 42161 + currency: ETH + polygon: + rpc: https://rpc.ankr.com/polygon + chain-id: 137 + network-id: 137 + currency: POL + bsc: + rpc: https://rpc.ankr.com/bsc + chain-id: 56 + network-id: 56 + currency: BNB + ethereum: + rpc: https://rpc.ankr.com/eth + chain-id: 1 + network-id: 1 + currency: ETH + linea: + rpc: https://rpc.linea.build + chain-id: 59144 + network-id: 59144 + currency: ETH + +metaboards: + flare: https://api.goldsky.com/api/public/project_clv14x04y9kzi01saerx7bxpg/subgraphs/mb-flare-0x893BBFB7/0.1/gn + base: https://api.goldsky.com/api/public/project_clv14x04y9kzi01saerx7bxpg/subgraphs/mb-base-0x59401C93/0.1/gn + arbitrum: https://api.goldsky.com/api/public/project_clv14x04y9kzi01saerx7bxpg/subgraphs/mb-arbitrum/0.1/gn + polygon: https://api.goldsky.com/api/public/project_clv14x04y9kzi01saerx7bxpg/subgraphs/mb-polygon/0.1/gn + bsc: https://api.goldsky.com/api/public/project_clv14x04y9kzi01saerx7bxpg/subgraphs/mb-bsc/0.1/gn + ethereum: https://api.goldsky.com/api/public/project_clv14x04y9kzi01saerx7bxpg/subgraphs/metadata-mainnet/2024-10-25-2857/gn + linea: https://api.goldsky.com/api/public/project_clv14x04y9kzi01saerx7bxpg/subgraphs/mb-linea-0xed7d6156/1.0.0/gn + +subgraphs: + flare: https://example.com/subgraph + base: https://example.com/subgraph + arbitrum: https://example.com/subgraph + polygon: https://example.com/subgraph + bsc: https://example.com/subgraph + ethereum: https://example.com/subgraph + linea: https://example.com/subgraph + +orderbooks: + flare: + address: 0xCEe8Cd002F151A536394E564b84076c41bBBcD4d + base: + address: 0xd2938e7c9fe3597f78832ce780feb61945c377d7 + network: base + subgraph: base + arbitrum: + address: 0x550878091b2B1506069F61ae59e3A5484Bca9166 + network: arbitrum + subgraph: arbitrum + polygon: + address: 0x7D2f700b1f6FD75734824EA4578960747bdF269A + network: polygon + subgraph: polygon + bsc: + address: 0xd2938E7c9fe3597F78832CE780Feb61945c377d7 + network: bsc + subgraph: bsc + ethereum: + address: 0x0eA6d458488d1cf51695e1D6e4744e6FB715d37C + network: ethereum + subgraph: ethereum + linea: + address: 0x22410e2a46261a1B1e3899a072f303022801C764 + network: linea + subgraph: linea + +deployers: + flare: + address: 0xE3989Ea7486c0F418C764e6c511e86f6E8830FAb + base: + address: 0xC1A14cE2fd58A3A2f99deCb8eDd866204eE07f8D + network: base + arbitrum: + address: 0x9B0D254bd858208074De3d2DaF5af11b3D2F377F + network: arbitrum + polygon: + address: 0xE7116BC05C8afe25e5B54b813A74F916B5D42aB1 + network: polygon + ethereum: + address: 0xd19581a021f4704ad4eBfF68258e7A0a9DB1CD77 + network: ethereum + linea: + address: 0xA2f56F8F74B7d04d61f281BE6576b6155581dcBA + network: linea + bsc: + address: 0xA2f56F8F74B7d04d61f281BE6576b6155581dcBA + network: bsc + +tokens: + arbitrum-usdc: + network: arbitrum + address: 0xaf88d065e77c8cC2239327C5EDb3A432268e5831 + decimals: 6 + arbitrum-wbtc: + network: arbitrum + address: 0x2f2a2543B76A4166549F7aaB2e75Bef0aefC5B0f + decimals: 8 + arbitrum-weth: + network: arbitrum + address: 0x82aF49447D8a07e3bd95BD0d56f35241523fBab1 + decimals: 18 + arbitrum-umja: + network: arbitrum + address: 0x16A500Aec6c37F84447ef04E66c57cfC6254cF92 + decimals: 18 + arbitrum-glo: + network: arbitrum + address: 0x4F604735c1cF31399C6E711D5962b2B3E0225AD3 + decimals: 18 + arbitrum-lusd: + network: arbitrum + address: 0x93b346b6BC2548dA6A1E7d98E9a421B42541425b + decimals: 18 + arbitrum-usdt: + network: arbitrum + address: 0xFd086bC7CD5C481DCC9C85ebE478A1C0b69FCbb9 + decimals: 6 + arbitrum-kima: + network: arbitrum + address: 0x94fCD9c18f99538C0f7C61c5500cA79F0D5C4dab + decimals: 18 + base-toshi: + network: base + address: 0xac1bd2486aaf3b5c0fc3fd868558b082a531b2b4 + decimals: 18 + base-usdc: + network: base + address: 0x833589fcd6edb6e08f4c7c32d4f71b54bda02913 + decimals: 6 + base-weth: + network: base + address: 0x4200000000000000000000000000000000000006 + decimals: 18 + base-paid: + network: base + address: 0x655A51e6803faF50D4acE80fa501af2F29C856cF + decimals: 18 + flare-usdce: + network: flare + address: 0xfbda5f676cb37624f28265a144a48b0d6e87d3b6 + decimals: 6 + flare-wflr: + network: flare + address: 0x1D80c49BbBCd1C0911346656B529DF9E5c2F783d + decimals: 18 + flare-sflr: + network: flare + address: 0x12e605bc104e93B45e1aD99F9e555f659051c2BB + decimals: 18 + flare-weth: + network: flare + address: 0x1502FA4be69d526124D453619276FacCab275d3D + decimals: 18 + flare-cysflr: + network: flare + address: 0x19831cfB53A0dbeAD9866C43557C1D48DfF76567 + flare-cusdx: + network: flare + address: 0xFE2907DFa8DB6e320cDbF45f0aa888F6135ec4f8 + flare-joule: + network: flare + address: 0xE6505f92583103AF7ed9974DEC451A7Af4e3A3bE + decimals: 18 + polygon-wmatic: + network: polygon + address: 0x0d500B1d8E8eF31E21C99d1Db9A6444d3ADf1270 + decimals: 18 + polygon-poli: + network: polygon + address: 0x6fb54Ffe60386aC33b722be13d2549dd87BF63AF + decimals: 18 + polygon-quick-old: + network: polygon + address: 0x831753dd7087cac61ab5644b308642cc1c33dc13 + decimals: 18 + polygon-quick: + network: polygon + address: 0xB5C064F955D8e7F38fE0460C556a72987494eE17 + decimals: 18 + polygon-ioen: + network: polygon + address: 0xd0e9c8f5Fae381459cf07Ec506C1d2896E8b5df6 + decimals: 18 + polygon-mnw: + network: polygon + address: 0x3c59798620e5fEC0Ae6dF1A19c6454094572Ab92 + decimals: 18 + polygon-gfi: + network: polygon + address: 0x874e178a2f3f3f9d34db862453cd756e7eab0381 + decimals: 18 + polygon-usdc: + network: polygon + address: 0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359 + decimals: 6 + polygon-usdt: + network: polygon + address: 0xc2132D05D31c914a87C6611C10748AEb04B58e8F + decimals: 6 + polygon-nht: + network: polygon + address: 0x84342e932797FC62814189f01F0Fb05F52519708 + decimals: 18 + polygon-weth: + network: polygon + address: 0x7ceB23fD6bC0adD59E62ac25578270cFf1b9f619 + decimals: 18 + polygon-usdce: + network: polygon + address: 0x2791bca1f2de4661ed88a30c99a7a9449aa84174 + decimals: 6 + bsc-tft: + network: bsc + address: 0x8f0FB159380176D324542b3a7933F0C2Fd0c2bbf + decimals: 7 + bsc-busd: + network: bsc + address: 0xe9e7CEA3DedcA5984780Bafc599bD69ADd087D56 + decimals: 18 + bsc-usdc: + network: bsc + address: 0x8AC76a51cc950d9822D68b83fE1Ad97B32Cd580d + decimals: 18 + base-wlth: + network: base + address: 0x99b2B1A2aDB02B38222ADcD057783D7e5D1FCC7D + decimals: 18 + ethereum-pai: + network: ethereum + address: 0x13E4b8CfFe704d3De6F19E52b201d92c21EC18bD + decimals: 18 + ethereum-mnw: + network: ethereum + address: 0xd3E4Ba569045546D09CF021ECC5dFe42b1d7f6E4 + decimals: 18 + ethereum-weth: + network: ethereum + address: 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2 + decimals: 18 + linea-clip: + network: linea + address: 0x4Ea77a86d6E70FfE8Bb947FC86D68a7F086f198a + decimals: 18 + linea-weth: + network: linea + address: 0xe5D7C2a44FfDDf6b295A15c148167daaAf5Cf34f + decimals: 18 + base-blood: + network: base + address: 0x3982E57fF1b193Ca8eb03D16Db268Bd4B40818f8 + decimals: 18 + base-lucky: + network: base + address: 0x2C002ffEC41568d138Acc36f5894d6156398D539 + decimals: 18 + +orders: + arbitrum-wbtc-weth: + network: arbitrum + orderbook: arbitrum + inputs: + - token: arbitrum-wbtc + - token: arbitrum-weth + outputs: + - token: arbitrum-wbtc + - token: arbitrum-weth + arbitrum-usdc-weth: + network: arbitrum + orderbook: arbitrum + inputs: + - token: arbitrum-usdc + - token: arbitrum-weth + outputs: + - token: arbitrum-usdc + - token: arbitrum-weth + arbitrum-usdt-kima: + network: arbitrum + orderbook: arbitrum + inputs: + - token: arbitrum-usdt + - token: arbitrum-kima + outputs: + - token: arbitrum-usdt + - token: arbitrum-kima + arbitrum-weth-umja: + network: arbitrum + orderbook: arbitrum + inputs: + - token: arbitrum-weth + - token: arbitrum-umja + outputs: + - token: arbitrum-weth + - token: arbitrum-umja + arbitrum-glo-lusd: + network: arbitrum + orderbook: arbitrum + inputs: + - token: arbitrum-glo + - token: arbitrum-lusd + outputs: + - token: arbitrum-glo + - token: arbitrum-lusd + base-usdc-weth: + network: base + orderbook: base + inputs: + - token: base-usdc + - token: base-weth + outputs: + - token: base-usdc + - token: base-weth + base-lucky-weth: + network: base + orderbook: base + inputs: + - token: base-lucky + - token: base-weth + outputs: + - token: base-lucky + - token: base-weth + base-usdc-toshi: + network: base + orderbook: base + inputs: + - token: base-usdc + - token: base-toshi + outputs: + - token: base-usdc + - token: base-toshi + base-usdc-paid: + network: base + orderbook: base + inputs: + - token: base-usdc + - token: base-paid + outputs: + - token: base-usdc + - token: base-paid + flare-usdce-sflr: + network: flare + orderbook: flare + inputs: + - token: flare-sflr + - token: flare-usdce + outputs: + - token: flare-sflr + - token: flare-usdce + flare-sflr-wflr: + network: flare + orderbook: flare + inputs: + - token: flare-sflr + - token: flare-wflr + outputs: + - token: flare-sflr + - token: flare-wflr + flare-cusdx-cysflr: + network: flare + orderbook: flare + inputs: + - token: flare-cusdx + - token: flare-cysflr + outputs: + - token: flare-cusdx + - token: flare-cysflr + flare-sflr-joule: + network: flare + orderbook: flare + inputs: + - token: flare-sflr + - token: flare-joule + outputs: + - token: flare-sflr + - token: flare-joule + flare-usdce-weth: + network: flare + orderbook: flare + inputs: + - token: flare-usdce + - token: flare-weth + outputs: + - token: flare-usdce + - token: flare-weth + flare-usdce-wflr: + network: flare + orderbook: flare + inputs: + - token: flare-usdce + - token: flare-wflr + outputs: + - token: flare-usdce + - token: flare-wflr + flare-usdce-cusdx: + network: flare + orderbook: flare + inputs: + - token: flare-usdce + - token: flare-cusdx + outputs: + - token: flare-usdce + - token: flare-cusdx + polygon-quick-old-quick: + network: polygon + orderbook: polygon + inputs: + - token: polygon-quick-old + - token: polygon-quick + outputs: + - token: polygon-quick-old + - token: polygon-quick + polygon-quick-wmatic: + network: polygon + orderbook: polygon + inputs: + - token: polygon-quick + - token: polygon-wmatic + outputs: + - token: polygon-quick + - token: polygon-wmatic + polygon-usdc-ioen: + network: polygon + orderbook: polygon + inputs: + - token: polygon-usdc + - token: polygon-ioen + outputs: + - token: polygon-usdc + - token: polygon-ioen + polygon-usdc-mnw: + network: polygon + orderbook: polygon + inputs: + - token: polygon-usdc + - token: polygon-mnw + outputs: + - token: polygon-usdc + - token: polygon-mnw + polygon-usdt-poli: + network: polygon + orderbook: polygon + inputs: + - token: polygon-usdt + - token: polygon-poli + outputs: + - token: polygon-usdt + - token: polygon-poli + polygon-weth-mnw: + network: polygon + orderbook: polygon + inputs: + - token: polygon-weth + - token: polygon-mnw + outputs: + - token: polygon-weth + - token: polygon-mnw + polygon-usdt-nht: + network: polygon + orderbook: polygon + inputs: + - token: polygon-usdt + - token: polygon-nht + outputs: + - token: polygon-usdt + - token: polygon-nht + polygon-usdce-gfi: + network: polygon + orderbook: polygon + inputs: + - token: polygon-usdce + - token: polygon-gfi + outputs: + - token: polygon-usdce + - token: polygon-gfi + bsc-tft-busd: + network: bsc + orderbook: bsc + inputs: + - token: bsc-tft + - token: bsc-busd + outputs: + - token: bsc-tft + - token: bsc-busd + bsc-tft-usdc: + network: bsc + orderbook: bsc + inputs: + - token: bsc-tft + - token: bsc-usdc + outputs: + - token: bsc-tft + - token: bsc-usdc + base-wlth-usdc: + network: base + orderbook: base + inputs: + - token: base-wlth + - token: base-usdc + outputs: + - token: base-wlth + - token: base-usdc + ethereum-pai-weth: + network: ethereum + orderbook: ethereum + inputs: + - token: ethereum-pai + - token: ethereum-weth + outputs: + - token: ethereum-pai + - token: ethereum-weth + ethereum-mnw-weth: + network: ethereum + orderbook: ethereum + inputs: + - token: ethereum-mnw + - token: ethereum-weth + outputs: + - token: ethereum-mnw + - token: ethereum-weth + linea-clip-weth: + network: linea + orderbook: linea + inputs: + - token: linea-clip + - token: linea-weth + outputs: + - token: linea-clip + - token: linea-weth + base-usdc-blood: + network: base + orderbook: base + inputs: + - token: base-usdc + - token: base-blood + outputs: + - token: base-usdc + - token: base-blood + +deployments: + arbitrum-wbtc-weth: + order: arbitrum-wbtc-weth + scenario: arbitrum.wbtc-weth + arbitrum-usdc-weth: + order: arbitrum-usdc-weth + scenario: arbitrum.usdc-weth + arbitrum-usdt-kima: + order: arbitrum-usdt-kima + scenario: arbitrum.usdt-kima + arbitrum-weth-umja: + order: arbitrum-weth-umja + scenario: arbitrum.weth-umja + arbitrum-glo-lusd: + order: arbitrum-glo-lusd + scenario: arbitrum.glo-lusd + base-usdc-weth: + order: base-usdc-weth + scenario: base.usdc-weth + base-lucky-weth: + order: base-lucky-weth + scenario: base.lucky-weth + base-usdc-toshi: + order: base-usdc-toshi + scenario: base.usdc-toshi + base-usdc-paid: + order: base-usdc-paid + scenario: base.usdc-paid + flare-usdce-sflr: + order: flare-usdce-sflr + scenario: flare.usdce-sflr + flare-sflr-wflr: + order: flare-sflr-wflr + scenario: flare.sflr-wflr + flare-cusdx-cysflr: + order: flare-cusdx-cysflr + scenario: flare.cusdx-cysflr + flare-usdce-weth: + order: flare-usdce-weth + scenario: flare.usdce-weth + flare-usdce-wflr: + order: flare-usdce-wflr + scenario: flare.usdce-wflr + flare-usdce-cusdx: + order: flare-usdce-cusdx + scenario: flare.usdce-cusdx + flare-sflr-joule: + order: flare-sflr-joule + scenario: flare.sflr-joule + polygon-quick-old-quick: + order: polygon-quick-old-quick + scenario: polygon.quick-old-quick + polygon-quick-wmatic: + order: polygon-quick-wmatic + scenario: polygon.quick-wmatic + polygon-usdc-ioen: + order: polygon-usdc-ioen + scenario: polygon.usdc-ioen + polygon-usdc-mnw: + order: polygon-usdc-mnw + scenario: polygon.usdc-mnw + polygon-usdt-poli: + order: polygon-usdt-poli + scenario: polygon.usdt-poli + polygon-weth-mnw: + order: polygon-weth-mnw + scenario: polygon.weth-mnw + polygon-usdt-nht: + order: polygon-usdt-nht + scenario: polygon.usdt-nht + polygon-usdce-gfi: + order: polygon-usdce-gfi + scenario: polygon.usdce-gfi + bsc-tft-busd: + order: bsc-tft-busd + scenario: bsc.tft-busd + bsc-tft-usdc: + order: bsc-tft-usdc + scenario: bsc.tft-usdc + base-wlth-usdc: + order: base-wlth-usdc + scenario: base.wlth-usdc + ethereum-pai-weth: + order: ethereum-pai-weth + scenario: ethereum.pai-weth + ethereum-mnw-weth: + order: ethereum-mnw-weth + scenario: ethereum.mnw-weth + linea-clip-weth: + order: linea-clip-weth + scenario: linea.clip-weth + base-usdc-blood: + order: base-usdc-blood + scenario: base.usdc-blood + +--- +#raindex-subparser !Subparser for the Raindex. + +#min-amount !Amount will decay down to this number each epoch. +#max-amount !Amount will decay down from this number each epoch. +#time-per-epoch !Duration of one unit of streaming amount and io ratio halflife. +#shy-epoch !Epoch below which only the minimum amount is offered. +#next-trade-multiplier !Start next auction at this x the last trade. +#history-cap !The max amount of trade history kept for cost basis tracking (denominated in same token as tranche size). +#amount-token !The token that is the amount token for the strategy. This denominates tranche sizes. +#initial-io !The IO ratio that the strategy starts at. The quote token is the output so that the IO ratio looks like a CEX price. +#initial-output-token !Initial output token for the initial IO ratio. +#initial-input-token !Initial input token for the initial IO ratio. +#cost-basis-multiplier !Multiplier for the cost basis IO ratio. Effectively a minimum spread. + +#is-fast-exit !Non-zero for fast exit behaviour. + +#last-trade-io-key "last-trade-io" +#last-trade-time-key "last-trade-time" +#last-trade-output-token-key "last-trade-output-token" +#vwaio-key "cost-basis-io-ratio" + +#amount-is-output + _: equal-to(amount-token output-token()); + +#get-cost-basis-io-ratio + this-total-out-key: hash(order-hash() input-token() output-token()), + this-vwaio-key: hash(this-total-out-key vwaio-key), + other-total-out-key: hash(order-hash() output-token() input-token()), + other-vwaio-key: hash(other-total-out-key vwaio-key), + + this-total-out: get(this-total-out-key), + other-total-out: get(other-total-out-key), + + this-vwaio: get(this-vwaio-key), + other-vwaio: get(other-vwaio-key); + +#set-cost-basis-io-ratio + /* first reduce outstanding inventory */ + this-total-out-key + this-vwaio-key + other-total-out-key + other-vwaio-key + this-total-out + other-total-out + this-vwaio + other-vwaio: call<'get-cost-basis-io-ratio>(), + + other-reduction-out: min(other-total-out input-vault-increase()), + reduced-other-total-out: sub(other-total-out other-reduction-out), + + :set(other-total-out-key reduced-other-total-out), + :set(other-vwaio-key every(reduced-other-total-out other-vwaio)), + + /* then increase our inventory */ + this-total-in: mul(this-total-out this-vwaio), + this-remaining-in: sub(input-vault-increase() other-reduction-out), + this-new-in: add(this-total-in this-remaining-in), + this-remaining-out: div(this-remaining-in calculated-io-ratio()), + this-new-out: add(this-total-out this-remaining-out), + this-new-vwaio: every(this-new-out div(this-new-in any(this-new-out max-value()))), + cap-out: if(call<'amount-is-output>() history-cap div(history-cap any(this-new-vwaio calculated-io-ratio()))), + capped-out: min(this-new-out cap-out), + + :set(this-total-out-key capped-out), + :set(this-vwaio-key this-new-vwaio); + +#halflife +epoch:, +/** + * Shrinking the multiplier like this + * then applying it 10 times allows for + * better precision when max-io-ratio + * is very large, e.g. ~1e10 or ~1e20+ + * + * This works because `power` loses + * precision on base `0.5` when the + * exponent is large and can even go + * to `0` while the io-ratio is still + * large. Better to keep the multiplier + * higher precision and drop the io-ratio + * smoothly for as long as we can. + */ +multiplier: + power(0.5 div(epoch 10)), +val: + mul( + multiplier + multiplier + multiplier + multiplier + multiplier + multiplier + multiplier + multiplier + multiplier + multiplier + ); + +#set-last-trade +last-io:, +:set(hash(order-hash() last-trade-time-key) now()), +:set(hash(order-hash() last-trade-io-key) last-io), +:set(hash(order-hash() last-trade-output-token-key) output-token()); + +#handle-add-order +using-words-from raindex-subparser +:set(hash(order-hash() last-trade-time-key) now()), +:set(hash(order-hash() last-trade-io-key) initial-io), +:set(hash(order-hash() last-trade-output-token-key) initial-output-token), +this-total-out-key: hash(order-hash() initial-input-token initial-output-token), +:set(this-total-out-key 1e-18), +:set(hash(this-total-out-key vwaio-key) initial-io); + +#get-last-trade +stored-last-io:get(hash(order-hash() last-trade-io-key)), +stored-last-output-token:get(hash(order-hash() last-trade-output-token-key)), +last-time:get(hash(order-hash() last-trade-time-key)), +_: if(equal-to(stored-last-output-token output-token()) stored-last-io inv(stored-last-io)); + +#get-epoch +last-time _: call<'get-last-trade>(), +duration: sub(now() last-time), +epochs: div(duration time-per-epoch); + +#amount-for-epoch +epoch io:, +decay: call<'halflife>(epoch), +shy-decay: every(greater-than(epoch shy-epoch) decay), +variable-component: sub(max-amount min-amount), +base-amount: add(min-amount mul(variable-component shy-decay)), +_: if(call<'amount-is-output>() base-amount mul(base-amount inv(io))); + +#io-for-epoch +epoch:, +last-io: call<'get-last-trade>(), +this-vwaio +other-vwaio: call<'get-cost-basis-io-ratio>(), +cost-basis-io: mul(any(this-vwaio inv(any(other-vwaio max-value()))) cost-basis-multiplier), +max-next-trade: mul(max(cost-basis-io last-io) next-trade-multiplier), +baseline: any(cost-basis-io last-io), +variable-component: sub(max-next-trade baseline), +decay: call<'halflife>(epoch), +above-baseline: mul(variable-component decay), +_: add(baseline above-baseline); + +#calculate-io +using-words-from raindex-subparser +epoch:call<'get-epoch>(), +io: call<'io-for-epoch>(epoch), +epoch-max-output: call<'amount-for-epoch>(epoch io), +other-total-out +_ +other-vwaio: call<'get-cost-basis-io-ratio>(), +max-output: max( + epoch-max-output + every( + is-fast-exit + mul(other-total-out other-vwaio))), +_: io, +:call<'set-last-trade>(io); + +#handle-io +min-trade-amount: mul(min-amount 0.9), +:ensure( + greater-than-or-equal-to( + if(call<'amount-is-output>() output-vault-decrease() input-vault-increase()) + min-trade-amount) + "Min trade amount."), +:call<'set-cost-basis-io-ratio>(); \ No newline at end of file From 83d8d6fea36fa42590c15b1ae211cc06259a4fa7 Mon Sep 17 00:00:00 2001 From: Jamie Harding Date: Sun, 5 Jan 2025 22:00:32 +0100 Subject: [PATCH 036/142] load strat --- .../webapp/src/routes/deployment/+page.svelte | 80 +++++++++---------- 1 file changed, 40 insertions(+), 40 deletions(-) diff --git a/packages/webapp/src/routes/deployment/+page.svelte b/packages/webapp/src/routes/deployment/+page.svelte index a0be2d756..d91b4b4d3 100644 --- a/packages/webapp/src/routes/deployment/+page.svelte +++ b/packages/webapp/src/routes/deployment/+page.svelte @@ -36,7 +36,6 @@ let gui: DotrainOrderGui | undefined = undefined; let availableDeployments: Record = {}; async function initialize() { - console.log('dotrain', dotrain); try { let deployments: AvailableDeployments = await DotrainOrderGui.getAvailableDeployments(dotrain); @@ -178,45 +177,46 @@
-
-
- - - - {#if selectedRef === undefined} - Select a deployment - {:else if selectedOption?.label} - {selectedOption.label} - {:else} - {selectedRef} - {/if} - - - -
-
{option.label ? option.label : ref}
-
-
-
-
- -
- {#if gui} - - {/if} -
+ {#if dotrain} +
+ + + + {#if selectedRef === undefined} + Select a deployment + {:else if selectedOption?.label} + {selectedOption.label} + {:else} + {selectedRef} + {/if} + + + +
+
{option.label ? option.label : ref}
+
+
+
+
+ +
+ {#if gui} + + {/if} +
+ {/if}
From 9b9e9d55e2da5342a26bad3fecf4e28f8db46c7a Mon Sep 17 00:00:00 2001 From: Jamie Harding Date: Sun, 5 Jan 2025 22:03:10 +0100 Subject: [PATCH 037/142] fix test --- packages/ui-components/src/__tests__/DepositButtons.test.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/ui-components/src/__tests__/DepositButtons.test.ts b/packages/ui-components/src/__tests__/DepositButtons.test.ts index 532a136c2..dce341df8 100644 --- a/packages/ui-components/src/__tests__/DepositButtons.test.ts +++ b/packages/ui-components/src/__tests__/DepositButtons.test.ts @@ -15,8 +15,7 @@ describe('DepositButtons', () => { const mockTokenInfos = new Map([['0x123', { name: 'Test Token', symbol: 'TEST' }]]); const mockDeposit: GuiDeposit = { - token: { address: '0x123' }, - token_name: 'TEST', + token: { address: '0x123', key: 'TEST' }, presets: ['100', '200', '300'] } as unknown as GuiDeposit; From 39beb58ad6cdbeaa8c0040d38d799b4703ffee0f Mon Sep 17 00:00:00 2001 From: Jamie Harding Date: Sun, 5 Jan 2025 22:11:27 +0100 Subject: [PATCH 038/142] ignore markdown --- packages/webapp/.prettierignore | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/webapp/.prettierignore b/packages/webapp/.prettierignore index ab78a95dd..13605c0b5 100644 --- a/packages/webapp/.prettierignore +++ b/packages/webapp/.prettierignore @@ -2,3 +2,4 @@ package-lock.json pnpm-lock.yaml yarn.lock +*.md \ No newline at end of file From 0b3721a64268110614d0f3c962e010497ddce76a Mon Sep 17 00:00:00 2001 From: Jamie Harding Date: Sun, 5 Jan 2025 23:08:01 +0100 Subject: [PATCH 039/142] lint --- packages/webapp/src/routes/deployment/+page.svelte | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/webapp/src/routes/deployment/+page.svelte b/packages/webapp/src/routes/deployment/+page.svelte index d91b4b4d3..06cdc9c19 100644 --- a/packages/webapp/src/routes/deployment/+page.svelte +++ b/packages/webapp/src/routes/deployment/+page.svelte @@ -11,7 +11,7 @@ type TokenInfos, type Vault } from '@rainlanguage/orderbook/js_api'; - import { Button, Input, Label } from 'flowbite-svelte'; + import { Button, Label } from 'flowbite-svelte'; import { createWalletClient, custom, type Chain } from 'viem'; import { base, flare, arbitrum, polygon, bsc, mainnet, linea } from 'viem/chains'; import testStrategy from './test-strategy.md?raw'; From 55ab1a0f1fe22f65c4fb93b92d39091c846561bd Mon Sep 17 00:00:00 2001 From: Jamie Harding Date: Mon, 6 Jan 2025 12:40:41 +0100 Subject: [PATCH 040/142] move to component --- .../deployment/DeploymentSteps.svelte | 308 ++++++++++++++---- .../components/deployment/test-strategy.rain} | 0 packages/webapp/.prettierignore | 3 +- .../webapp/src/routes/deployment/+page.svelte | 219 +------------ 4 files changed, 248 insertions(+), 282 deletions(-) rename packages/{webapp/src/routes/deployment/test-strategy.md => ui-components/src/lib/components/deployment/test-strategy.rain} (100%) diff --git a/packages/ui-components/src/lib/components/deployment/DeploymentSteps.svelte b/packages/ui-components/src/lib/components/deployment/DeploymentSteps.svelte index 473ba595a..ea0cf99a4 100644 --- a/packages/ui-components/src/lib/components/deployment/DeploymentSteps.svelte +++ b/packages/ui-components/src/lib/components/deployment/DeploymentSteps.svelte @@ -3,79 +3,259 @@ import DepositButtons from './DepositButtons.svelte'; import SelectToken from './SelectToken.svelte'; import TokenInputOrOutput from './TokenInputOrOutput.svelte'; + import DropdownRadio from '../dropdown/DropdownRadio.svelte'; - import type { + import { DotrainOrderGui, - GuiDeposit, - GuiFieldDefinition, - SelectTokens, - TokenInfos, - Vault + type ApprovalCalldataResult, + type AvailableDeployments, + type DepositAndAddOrderCalldataResult, + type GuiDeposit, + type GuiFieldDefinition, + type SelectTokens, + type TokenInfos, + type Vault } from '@rainlanguage/orderbook/js_api'; import { Button, Label } from 'flowbite-svelte'; - export let gui: DotrainOrderGui; - - export let selectTokens: SelectTokens; - export let allFieldDefinitions: GuiFieldDefinition[]; - export let allTokenInputs: Vault[]; - export let allTokenOutputs: Vault[]; - export let allDeposits: GuiDeposit[]; - export let inputVaultIds: string[]; - export let outputVaultIds: string[]; - export let isLimitStrat: boolean; - export let handleAddOrder: () => Promise; - export let tokenInfos: TokenInfos; + import { createWalletClient, custom, type Chain } from 'viem'; + import { base, flare, arbitrum, polygon, bsc, mainnet, linea } from 'viem/chains'; + import testStrategy from './test-strategy.rain?raw'; + + const chains: Record = { + [base.id]: base, + [flare.id]: flare, + [arbitrum.id]: arbitrum, + [polygon.id]: polygon, + [bsc.id]: bsc, + [mainnet.id]: mainnet, + [linea.id]: linea + }; + + let dotrain = ''; + let isLimitStrat = false; + + async function loadStrategy() { + dotrain = testStrategy; + } + + let gui: DotrainOrderGui | undefined = undefined; + let availableDeployments: Record = {}; + async function initialize() { + try { + let deployments: AvailableDeployments = + await DotrainOrderGui.getAvailableDeployments(dotrain); + availableDeployments = Object.fromEntries( + deployments.map((deployment) => [ + deployment.key, + { + label: deployment.key, + deployment + } + ]) + ); + } catch (error) { + // eslint-disable-next-line no-console + console.error('Failed to load deployments:', error); + } + } + $: if (dotrain) { + initialize(); + } + + let selectedDeployment: string | undefined = undefined; + async function handleDeploymentChange(deployment: string) { + if (!deployment) return; + + try { + gui = await DotrainOrderGui.chooseDeployment(dotrain, deployment); + initializeVaultIdArrays(); + } catch (error) { + // eslint-disable-next-line no-console + console.error('Failed to get gui:', error); + } + } + + $: if (selectedDeployment) { + handleDeploymentChange(selectedDeployment as string); + } + + let tokenInfos: TokenInfos; + function getTokenInfos() { + if (!gui) return; + tokenInfos = gui.getTokenInfos(); + } + + let selectTokens: SelectTokens = new Map(); + function getSelectTokens() { + if (!gui) return; + selectTokens = gui.getSelectTokens(); + } + + let allFieldDefinitions: GuiFieldDefinition[] = []; + function getAllFieldDefinitions() { + if (!gui) return; + allFieldDefinitions = gui.getAllFieldDefinitions(); + } + + let allDeposits: GuiDeposit[] = []; + function getDeposits() { + if (!gui) return; + allDeposits = gui.getCurrentDeployment().deposits; + } + + let allTokenInputs: Vault[] = []; + function getAllTokenInputs() { + if (!gui) return; + allTokenInputs = gui.getCurrentDeployment().deployment.order.inputs; + } + + let allTokenOutputs: Vault[] = []; + function getAllTokenOutputs() { + if (!gui) return; + allTokenOutputs = gui.getCurrentDeployment().deployment.order.outputs; + } + + $: if (gui) { + getTokenInfos(); + if (isLimitStrat) getSelectTokens(); + getAllFieldDefinitions(); + getDeposits(); + getAllTokenInputs(); + getAllTokenOutputs(); + } + + export function getChainById(chainId: number): Chain { + const chain = chains[chainId]; + if (!chain) { + throw new Error(`Unsupported chain ID: ${chainId}`); + } + return chain; + } + + async function handleAddOrder() { + try { + if (!gui) return; + + // @ts-expect-error window.ethereum is not typed + await window.ethereum?.request({ method: 'eth_requestAccounts' }); + const walletClient = createWalletClient({ + chain: getChainById( + gui.getCurrentDeployment().deployment.order.network['chain-id'] as number + ), + // @ts-expect-error window.ethereum is not typed + transport: custom(window.ethereum!) + }); + const [account] = await walletClient.getAddresses(); + + const approvals: ApprovalCalldataResult = await gui.generateApprovalCalldatas(account); + for (const approval of approvals) { + await walletClient.sendTransaction({ + account, + to: approval.token as `0x${string}`, + data: approval.calldata as `0x${string}` + }); + } + + const calldata: DepositAndAddOrderCalldataResult = + await gui.generateDepositAndAddOrderCalldatas(); + await walletClient.sendTransaction({ + account, + // @ts-expect-error orderbook is not typed + to: gui.getCurrentDeployment().deployment.order.orderbook.address as `0x${string}`, + data: calldata as `0x${string}` + }); + } catch (error) { + // eslint-disable-next-line no-console + console.error('Failed to add order:', error); + } + } + + let inputVaultIds: string[] = []; + let outputVaultIds: string[] = []; + function initializeVaultIdArrays() { + if (!gui) return; + const deployment = gui.getCurrentDeployment(); + inputVaultIds = new Array(deployment.deployment.order.inputs.length).fill(''); + outputVaultIds = new Array(deployment.deployment.order.outputs.length).fill(''); + } -
- {#if isLimitStrat && selectTokens.size > 0} - +
+ +
+{#if dotrain} +
+ + + + {#if selectedRef === undefined} + Select a deployment + {:else if selectedOption?.label} + {selectedOption.label} + {:else} + {selectedRef} + {/if} + - {#each selectTokens.entries() as [token]} - - {/each} - {/if} + +
+
{option.label ? option.label : ref}
+
+
+
+
+ {#if gui} +
+ {#if selectTokens.size > 0} + - {#if allFieldDefinitions.length > 0} - - {#each allFieldDefinitions as fieldDefinition} - - {/each} - {/if} + {#each selectTokens.entries() as [token]} + + {/each} + {/if} - {#if allDeposits.length > 0} - - {#each allDeposits as deposit} - - {/each} - {/if} + {#if allFieldDefinitions.length > 0} + + {#each allFieldDefinitions as fieldDefinition} + + {/each} + {/if} - {#if allTokenInputs.length > 0} - - {#each allTokenInputs as input, i} - - {/each} - {/if} + {#if allDeposits.length > 0} + + {#each allDeposits as deposit} + + {/each} + {/if} + + {#if allTokenInputs.length > 0} + + {#each allTokenInputs as input, i} + + {/each} + {/if} - {#if allTokenOutputs.length > 0} - - {#each allTokenOutputs as output, i} - - {/each} + {#if allTokenOutputs.length > 0} + + {#each allTokenOutputs as output, i} + + {/each} + {/if} + +
{/if} - -
+{/if} diff --git a/packages/webapp/src/routes/deployment/test-strategy.md b/packages/ui-components/src/lib/components/deployment/test-strategy.rain similarity index 100% rename from packages/webapp/src/routes/deployment/test-strategy.md rename to packages/ui-components/src/lib/components/deployment/test-strategy.rain diff --git a/packages/webapp/.prettierignore b/packages/webapp/.prettierignore index 13605c0b5..6d06c2d43 100644 --- a/packages/webapp/.prettierignore +++ b/packages/webapp/.prettierignore @@ -2,4 +2,5 @@ package-lock.json pnpm-lock.yaml yarn.lock -*.md \ No newline at end of file +*.md +*.rain \ No newline at end of file diff --git a/packages/webapp/src/routes/deployment/+page.svelte b/packages/webapp/src/routes/deployment/+page.svelte index 06cdc9c19..8edfae5bb 100644 --- a/packages/webapp/src/routes/deployment/+page.svelte +++ b/packages/webapp/src/routes/deployment/+page.svelte @@ -1,222 +1,7 @@
-
- -
- {#if dotrain} -
- - - - {#if selectedRef === undefined} - Select a deployment - {:else if selectedOption?.label} - {selectedOption.label} - {:else} - {selectedRef} - {/if} - - - -
-
{option.label ? option.label : ref}
-
-
-
-
- -
- {#if gui} - - {/if} -
- {/if} +
From 94e16db9efdcb316ff2eed8afba36419a9b891f9 Mon Sep 17 00:00:00 2001 From: Jamie Harding Date: Mon, 6 Jan 2025 13:58:15 +0100 Subject: [PATCH 041/142] add tests for deployment steps --- .../src/__tests__/DeploymentSteps.test.ts | 115 ++++++++++++++++++ .../components/dropdown/DropdownRadio.svelte | 1 + 2 files changed, 116 insertions(+) create mode 100644 packages/ui-components/src/__tests__/DeploymentSteps.test.ts diff --git a/packages/ui-components/src/__tests__/DeploymentSteps.test.ts b/packages/ui-components/src/__tests__/DeploymentSteps.test.ts new file mode 100644 index 000000000..efb944160 --- /dev/null +++ b/packages/ui-components/src/__tests__/DeploymentSteps.test.ts @@ -0,0 +1,115 @@ +import { describe, it, expect, vi, beforeEach, type Mock } from 'vitest'; +import { render, screen, fireEvent } from '@testing-library/svelte'; +import DeploymentSteps from '../lib/components/deployment/DeploymentSteps.svelte'; +import { DotrainOrderGui } from '@rainlanguage/orderbook/js_api'; +import testStrategy from '../lib/components/deployment/test-strategy.rain?raw'; + +vi.mock('@rainlanguage/orderbook/js_api', () => ({ + DotrainOrderGui: { + getAvailableDeployments: vi.fn(), + chooseDeployment: vi.fn() + } +})); + +describe('DeploymentSteps', () => { + beforeEach(() => { + vi.clearAllMocks(); + }); + + it('renders load strategy button', () => { + render(DeploymentSteps); + expect(screen.getByText('Load Strategy')).toBeInTheDocument(); + }); + + it('loads strategy when button is clicked', async () => { + render(DeploymentSteps); + const loadButton = screen.getByText('Load Strategy'); + + + const mockDeployments = [ + { key: 'deployment1', label: 'Deployment 1' }, + { key: 'deployment2', label: 'Deployment 2' } + ]; + + (DotrainOrderGui.getAvailableDeployments as Mock).mockResolvedValue(mockDeployments); + + await fireEvent.click(loadButton); + + + expect(DotrainOrderGui.getAvailableDeployments).toHaveBeenCalled(); + }); + + it('shows deployments dropdown after strategy is loaded', async () => { + render(DeploymentSteps); + const loadButton = screen.getByText('Load Strategy'); + + + const mockDeployments = [ + { key: 'deployment1', label: 'Deployment 1' }, + { key: 'deployment2', label: 'Deployment 2' } + ]; + + (DotrainOrderGui.getAvailableDeployments as Mock).mockResolvedValue(mockDeployments); + + await fireEvent.click(loadButton); + + expect(screen.getByText('Deployments')).toBeInTheDocument(); + expect(screen.getByText('Select a deployment')).toBeInTheDocument(); + }); + + it('initializes GUI when deployment is selected', async () => { + render(DeploymentSteps); + + const mockDeployments = [ + { key: 'deployment1', label: 'Deployment 1' }, + { key: 'deployment2', label: 'Deployment 2' } + ]; + + + const mockGui = { + getTokenInfos: vi.fn().mockReturnValue({}), + getCurrentDeployment: vi.fn().mockReturnValue({ + deposits: [], + deployment: { + order: { + inputs: [], + outputs: [] + } + } + }), + getAllFieldDefinitions: vi.fn().mockReturnValue([]) + }; + const loadButton = screen.getByText('Load Strategy'); + + (DotrainOrderGui.getAvailableDeployments as Mock).mockResolvedValue(mockDeployments); + + await fireEvent.click(loadButton); + + expect(screen.getByText('Deployments')).toBeInTheDocument(); + expect(screen.getByText('Select a deployment')).toBeInTheDocument(); + + (DotrainOrderGui.chooseDeployment as Mock).mockResolvedValue(mockGui); + + const dropdownButton = screen.getByTestId('dropdown-button'); + await fireEvent.click(dropdownButton); + const dropdown = screen.getByTestId('dropdown'); + await fireEvent.click(dropdown); + const deploymentOption = screen.getByText('deployment1'); + await fireEvent.click(deploymentOption); + + expect(DotrainOrderGui.chooseDeployment).toHaveBeenCalled(); + }); + + it('handles errors during deployment initialization', async () => { + const consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {}); + + (DotrainOrderGui.getAvailableDeployments as Mock).mockRejectedValue(new Error('Failed to load')); + + render(DeploymentSteps); + const loadButton = screen.getByText('Load Strategy'); + await fireEvent.click(loadButton); + + expect(consoleSpy).toHaveBeenCalledWith('Failed to load deployments:', expect.any(Error)); + consoleSpy.mockRestore(); + }); +}); \ No newline at end of file diff --git a/packages/ui-components/src/lib/components/dropdown/DropdownRadio.svelte b/packages/ui-components/src/lib/components/dropdown/DropdownRadio.svelte index 50da95644..84d7e9d0b 100644 --- a/packages/ui-components/src/lib/components/dropdown/DropdownRadio.svelte +++ b/packages/ui-components/src/lib/components/dropdown/DropdownRadio.svelte @@ -25,6 +25,7 @@ +
+ +{#if error} +

{error}

+{/if} +{#if errorDetails} +

{errorDetails}

+{/if} {#if dotrain}
@@ -203,6 +269,9 @@
+ {#if isLoading} + + {/if} {#if gui}
{#if selectTokens.size > 0} @@ -228,7 +297,7 @@ {/if} {#if allTokenInputs.length > 0} - + {#each allTokenInputs as input, i} 0} - + {#each allTokenOutputs as output, i} Date: Wed, 8 Jan 2025 12:00:28 +0100 Subject: [PATCH 046/142] update reactivity to checkdeposits against current value --- .../deployment/ButtonSelectOption.svelte | 15 ++ .../deployment/DeploymentSteps.svelte | 23 ++- .../deployment/DepositButtons.svelte | 47 +++--- .../components/deployment/SelectToken.svelte | 18 ++- .../test-strategy-token-select.rain | 148 +++++++++--------- 5 files changed, 146 insertions(+), 105 deletions(-) create mode 100644 packages/ui-components/src/lib/components/deployment/ButtonSelectOption.svelte diff --git a/packages/ui-components/src/lib/components/deployment/ButtonSelectOption.svelte b/packages/ui-components/src/lib/components/deployment/ButtonSelectOption.svelte new file mode 100644 index 000000000..4fdb958fc --- /dev/null +++ b/packages/ui-components/src/lib/components/deployment/ButtonSelectOption.svelte @@ -0,0 +1,15 @@ + + + diff --git a/packages/ui-components/src/lib/components/deployment/DeploymentSteps.svelte b/packages/ui-components/src/lib/components/deployment/DeploymentSteps.svelte index faa4b0a8d..0a41f6dce 100644 --- a/packages/ui-components/src/lib/components/deployment/DeploymentSteps.svelte +++ b/packages/ui-components/src/lib/components/deployment/DeploymentSteps.svelte @@ -109,16 +109,18 @@ let tokenInfos: TokenInfos; function getTokenInfos() { + console.log('getTokenInfos'); if (!gui) return; try { tokenInfos = gui.getTokenInfos(); + console.log(tokenInfos); } catch (e) { error = DeploymentStepErrors.NO_TOKEN_INFO; console.error('Failed to get token infos:', e); } } - let selectTokens: SelectTokens = new Map(); + let selectTokens: SelectTokens | null = null; function getSelectTokens() { if (!gui) return; try { @@ -127,6 +129,7 @@ console.error('Failed to get select tokens:', e); } } + let allFieldDefinitions: GuiFieldDefinition[] = []; function getAllFieldDefinitions() { if (!gui) return; @@ -171,6 +174,18 @@ } } + $: if (selectTokens) { + getTokenInfos(); + getDeposits(); + } + + $: if (gui) { + console.log('GUI CHANGED'); + console.log(gui.getDeposits); + } + + $: console.log('SELECT TOKENS!', selectTokens); + $: if (gui) { error = null; getTokenInfos(); @@ -274,11 +289,11 @@ {/if} {#if gui}
- {#if selectTokens.size > 0} + {#if selectTokens} {#each selectTokens.entries() as [token]} - + {/each} {/if} @@ -292,7 +307,7 @@ {#if allDeposits.length > 0} {#each allDeposits as deposit} - + {/each} {/if} diff --git a/packages/ui-components/src/lib/components/deployment/DepositButtons.svelte b/packages/ui-components/src/lib/components/deployment/DepositButtons.svelte index 786cd8681..60230c18c 100644 --- a/packages/ui-components/src/lib/components/deployment/DepositButtons.svelte +++ b/packages/ui-components/src/lib/components/deployment/DepositButtons.svelte @@ -2,24 +2,43 @@ import { DotrainOrderGui, type GuiDeposit, - type TokenInfos + type TokenInfos, + type TokenDeposit } from '@rainlanguage/orderbook/js_api'; - import { Input, Button } from 'flowbite-svelte'; + import { Input } from 'flowbite-svelte'; + import ButtonSelectOption from './ButtonSelectOption.svelte'; export let deposit: GuiDeposit; export let gui: DotrainOrderGui; export let tokenInfos: TokenInfos; + let currentDeposit: TokenDeposit | undefined; + + let tokenName = ''; + function handlePresetClick(preset: string) { gui?.saveDeposit(deposit.token.key, preset); gui = gui; + currentDeposit = gui?.getDeposits().find((d) => d.token === deposit.token.key); + } + + function handleInput(e: Event) { + if (e.currentTarget instanceof HTMLInputElement) { + gui?.saveDeposit(deposit.token.key, e.currentTarget.value); + gui = gui; + currentDeposit = gui?.getDeposits().find((d) => d.token === deposit.token.key); + } + } + + $: if (tokenInfos) { + tokenName = tokenInfos.get(deposit.token.address)?.name || deposit.token.key; }

- {tokenInfos.get(deposit.token.address)?.name} + {tokenName}

Select deposit amount

@@ -27,16 +46,11 @@ {#if deposit.presets}
{#each deposit.presets as preset} - + handlePresetClick(preset)} + /> {/each}
{/if} @@ -46,12 +60,7 @@ class="text-center text-lg" size="lg" placeholder="Enter deposit amount" - on:input={({ currentTarget }) => { - if (currentTarget instanceof HTMLInputElement) { - gui?.saveDeposit(deposit.token.key, currentTarget.value); - gui = gui; - } - }} + on:input={(e) => handleInput(e)} />
diff --git a/packages/ui-components/src/lib/components/deployment/SelectToken.svelte b/packages/ui-components/src/lib/components/deployment/SelectToken.svelte index 9020aa284..9acb117c9 100644 --- a/packages/ui-components/src/lib/components/deployment/SelectToken.svelte +++ b/packages/ui-components/src/lib/components/deployment/SelectToken.svelte @@ -5,19 +5,29 @@ export let token: string; export let gui: DotrainOrderGui; export let selectTokens: Map; + + let error = '';
{ + on:input={async ({ currentTarget }) => { if (currentTarget instanceof HTMLInputElement) { if (!gui) return; - await gui.saveSelectTokenAddress(token, currentTarget.value); - selectTokens = gui.getSelectTokens(); - gui = gui; + try { + await gui.saveSelectTokenAddress(token, currentTarget.value); + error = ''; + selectTokens = gui.getSelectTokens(); + gui = gui; + } catch { + error = 'Invalid address'; + } } }} /> + {#if error} +

{error}

+ {/if}
diff --git a/packages/ui-components/src/lib/components/deployment/test-strategy-token-select.rain b/packages/ui-components/src/lib/components/deployment/test-strategy-token-select.rain index 4ad8b4685..de3f07e61 100644 --- a/packages/ui-components/src/lib/components/deployment/test-strategy-token-select.rain +++ b/packages/ui-components/src/lib/components/deployment/test-strategy-token-select.rain @@ -1,95 +1,87 @@ +# Edit this to work with FLR + raindex-version: 8898591f3bcaa21dc91dc3b8584330fc405eadfa +networks: + flare: + rpc: https://rpc.ankr.com/flare + chain-id: 14 + +metaboards: + # What does metaboard do? + flare: https://api.goldsky.com/api/public/project_clv14x04y9kzi01saerx7bxpg/subgraphs/mb-flare-0x893BBFB7/0.1/gn +subgraphs: + flare: https://api.goldsky.com/api/public/project_clv14x04y9kzi01saerx7bxpg/subgraphs/ob4-flare/0.8/gn +orderbooks: + flare: + address: 0xCEe8Cd002F151A536394E564b84076c41bBBcD4d + network: flare + subgraph: flare +deployers: + flare: + address: 0xE3989Ea7486c0F418C764e6c511e86f6E8830FAb + network: flare +tokens: + # There needs to be tokens defined in the deployment, + # BUT select-tokens in GUI works as an override + token1: + network: flare + address: "0x0000000000000000000000000000000000000000" + token2: + network: flare + address: "0x0000000000000000000000000000000000000000" +orders: + flare-token1-token2: + orderbook: flare + network: flare + inputs: + - token: token1 + outputs: + - token: token2 +scenarios: + flare: + orderbook: flare + runs: 1 + bindings: + io-ratio: 10 +deployments: + flare-token1-token2: + order: flare-token1-token2 + scenario: flare gui: - name: Test test - description: Test test test + name: Fixed limit + description: > + Fixed limit order strategy deployments: - other-deployment: - name: Test test - description: Test test test + flare-token1-token2: + name: Buy token1 with token2 on flare. + description: + Buy token1 with token2 with a fixed ratio on flare network. deposits: - - token: token1 - min: 0 - presets: - - "0" - token: token2 min: 0 presets: - - "0" + - 0 + - 10 + - 100 + - 1000 + - 10000 fields: - - binding: test-binding - name: Test binding - description: Test binding description - presets: - - value: "test-value" + - binding: io-ratio + name: token1 to token2 ratio + description: How many inputs do you want to have per one output? + select-tokens: + # This is a required field! It overrides the tokens defined in the deployment. + # It's a list of tokens that will be used in the order. + # The names need to match the tokens defined in the deployment. - token1 - token2 - -networks: - some-network: - rpc: http://localhost:8085/rpc-url - chain-id: 123 - network-id: 123 - currency: ETH - -subgraphs: - some-sg: https://www.some-sg.com - -deployers: - some-deployer: - network: some-network - address: 0xF14E09601A47552De6aBd3A0B165607FaFd2B5Ba - -orderbooks: - some-orderbook: - address: 0xc95A5f8eFe14d7a20BD2E5BAFEC4E71f8Ce0B9A6 - network: some-network - subgraph: some-sg - -tokens: - token1: - network: some-network - address: 0xc2132d05d31c914a87c6611c10748aeb04b58e8f - decimals: 6 - label: Token 1 - symbol: T1 - token2: - network: some-network - address: 0x8f3cf7ad23cd3cadbd9735aff958023239c6a063 - decimals: 18 - label: Token 2 - symbol: T2 - -scenarios: - some-scenario: - network: some-network - deployer: some-deployer - bindings: - test-binding: "5" - -orders: - some-order: - inputs: - - token: token1 - vault-id: 1 - outputs: - - token: token2 - vault-id: 1 - deployer: some-deployer - orderbook: some-orderbook - -deployments: - some-deployment: - scenario: some-scenario - order: some-order - other-deployment: - scenario: some-scenario - order: some-order --- -#test-binding ! +#io-ratio !The io ratio for the limit order. #calculate-io -_ _: 0 0; +max-output: max-value(), +io: io-ratio; #handle-io :; #handle-add-order From 058d512495a9625c780b92885b9416148f249123 Mon Sep 17 00:00:00 2001 From: Jamie Harding Date: Wed, 8 Jan 2025 12:03:39 +0100 Subject: [PATCH 047/142] ignore rain in prettier --- packages/ui-components/.prettierignore | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/ui-components/.prettierignore b/packages/ui-components/.prettierignore index ab78a95dd..c2fb3dc7d 100644 --- a/packages/ui-components/.prettierignore +++ b/packages/ui-components/.prettierignore @@ -2,3 +2,4 @@ package-lock.json pnpm-lock.yaml yarn.lock +*.rain \ No newline at end of file From 6622482029f4a18a9ab980b0d318bf7912bc917f Mon Sep 17 00:00:00 2001 From: Jamie Harding Date: Wed, 8 Jan 2025 12:22:03 +0100 Subject: [PATCH 048/142] add check for current value --- .../deployment/FieldDefinitionButtons.svelte | 31 +++++++++++-------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/packages/ui-components/src/lib/components/deployment/FieldDefinitionButtons.svelte b/packages/ui-components/src/lib/components/deployment/FieldDefinitionButtons.svelte index 1564b2307..97b8764fc 100644 --- a/packages/ui-components/src/lib/components/deployment/FieldDefinitionButtons.svelte +++ b/packages/ui-components/src/lib/components/deployment/FieldDefinitionButtons.svelte @@ -1,17 +1,25 @@
@@ -36,17 +47,11 @@
{#if fieldDefinition.presets} {#each fieldDefinition.presets as preset} - + handlePresetClick(preset.id)} + active={currentFieldDefinition?.value === preset.value} + /> {/each} {/if}
From 8e4e4021f2b10003859ad355cc6f7da3fc3e273d Mon Sep 17 00:00:00 2001 From: Jamie Harding Date: Wed, 8 Jan 2025 12:46:55 +0100 Subject: [PATCH 049/142] add focus --- .../components/deployment/ButtonSelectOption.svelte | 2 +- .../lib/components/deployment/DepositButtons.svelte | 4 ++++ .../deployment/FieldDefinitionButtons.svelte | 12 +++++++----- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/packages/ui-components/src/lib/components/deployment/ButtonSelectOption.svelte b/packages/ui-components/src/lib/components/deployment/ButtonSelectOption.svelte index 4fdb958fc..fd3a12098 100644 --- a/packages/ui-components/src/lib/components/deployment/ButtonSelectOption.svelte +++ b/packages/ui-components/src/lib/components/deployment/ButtonSelectOption.svelte @@ -8,7 +8,7 @@
diff --git a/packages/ui-components/src/lib/components/deployment/FieldDefinitionButtons.svelte b/packages/ui-components/src/lib/components/deployment/FieldDefinitionButtons.svelte index 97b8764fc..5442c5115 100644 --- a/packages/ui-components/src/lib/components/deployment/FieldDefinitionButtons.svelte +++ b/packages/ui-components/src/lib/components/deployment/FieldDefinitionButtons.svelte @@ -12,17 +12,20 @@ export let gui: DotrainOrderGui; let currentFieldDefinition: GuiPreset | undefined; + let inputValue = ''; - function handlePresetClick(presetId: string) { + function handlePresetClick(preset: GuiPreset) { + inputValue = preset.value; gui?.saveFieldValue(fieldDefinition.binding, { isPreset: true, - value: presetId + value: preset.id }); gui = gui; currentFieldDefinition = gui?.getFieldValue(fieldDefinition.binding); } function handleCustomInputChange(value: string) { + inputValue = value; gui?.saveFieldValue(fieldDefinition.binding, { isPreset: false, value: value @@ -30,8 +33,6 @@ gui = gui; currentFieldDefinition = gui?.getFieldValue(fieldDefinition.binding); } - - $: console.log('current field definition', currentFieldDefinition);
@@ -49,7 +50,7 @@ {#each fieldDefinition.presets as preset} handlePresetClick(preset.id)} + clickHandler={() => handlePresetClick(preset)} active={currentFieldDefinition?.value === preset.value} /> {/each} @@ -61,6 +62,7 @@ class="text-center text-lg" size="lg" placeholder="Enter custom value" + bind:value={inputValue} on:input={({ currentTarget }) => { if (currentTarget instanceof HTMLInputElement) { handleCustomInputChange(currentTarget.value); From 445814a5d632f4d045aec6be51e7825c0af409a1 Mon Sep 17 00:00:00 2001 From: Jamie Harding Date: Wed, 8 Jan 2025 12:47:57 +0100 Subject: [PATCH 050/142] rm logs --- .../src/lib/components/deployment/DeploymentSteps.svelte | 9 --------- 1 file changed, 9 deletions(-) diff --git a/packages/ui-components/src/lib/components/deployment/DeploymentSteps.svelte b/packages/ui-components/src/lib/components/deployment/DeploymentSteps.svelte index 0a41f6dce..b0e6376fe 100644 --- a/packages/ui-components/src/lib/components/deployment/DeploymentSteps.svelte +++ b/packages/ui-components/src/lib/components/deployment/DeploymentSteps.svelte @@ -109,11 +109,9 @@ let tokenInfos: TokenInfos; function getTokenInfos() { - console.log('getTokenInfos'); if (!gui) return; try { tokenInfos = gui.getTokenInfos(); - console.log(tokenInfos); } catch (e) { error = DeploymentStepErrors.NO_TOKEN_INFO; console.error('Failed to get token infos:', e); @@ -179,13 +177,6 @@ getDeposits(); } - $: if (gui) { - console.log('GUI CHANGED'); - console.log(gui.getDeposits); - } - - $: console.log('SELECT TOKENS!', selectTokens); - $: if (gui) { error = null; getTokenInfos(); From ce12d7794e7d319176e60399ff4f0778a314068f Mon Sep 17 00:00:00 2001 From: Jamie Harding Date: Wed, 8 Jan 2025 12:55:05 +0100 Subject: [PATCH 051/142] rm notes --- .../components/deployment/test-strategy-token-select.rain | 7 ------- 1 file changed, 7 deletions(-) diff --git a/packages/ui-components/src/lib/components/deployment/test-strategy-token-select.rain b/packages/ui-components/src/lib/components/deployment/test-strategy-token-select.rain index de3f07e61..c0d4aef91 100644 --- a/packages/ui-components/src/lib/components/deployment/test-strategy-token-select.rain +++ b/packages/ui-components/src/lib/components/deployment/test-strategy-token-select.rain @@ -1,5 +1,3 @@ -# Edit this to work with FLR - raindex-version: 8898591f3bcaa21dc91dc3b8584330fc405eadfa networks: flare: @@ -21,8 +19,6 @@ deployers: address: 0xE3989Ea7486c0F418C764e6c511e86f6E8830FAb network: flare tokens: - # There needs to be tokens defined in the deployment, - # BUT select-tokens in GUI works as an override token1: network: flare address: "0x0000000000000000000000000000000000000000" @@ -72,9 +68,6 @@ gui: description: How many inputs do you want to have per one output? select-tokens: - # This is a required field! It overrides the tokens defined in the deployment. - # It's a list of tokens that will be used in the order. - # The names need to match the tokens defined in the deployment. - token1 - token2 --- From d351d7549c396d44a92888dd408a59a57afdc03b Mon Sep 17 00:00:00 2001 From: Jamie Harding Date: Thu, 9 Jan 2025 15:55:14 +0100 Subject: [PATCH 052/142] tests passing --- .../src/__tests__/SelectToken.test.ts | 55 ++++++++++--- .../deployment/DeploymentSteps.svelte | 4 +- .../components/deployment/SelectToken.svelte | 77 +++++++++++++------ 3 files changed, 100 insertions(+), 36 deletions(-) diff --git a/packages/ui-components/src/__tests__/SelectToken.test.ts b/packages/ui-components/src/__tests__/SelectToken.test.ts index 86cab19cd..444a649a7 100644 --- a/packages/ui-components/src/__tests__/SelectToken.test.ts +++ b/packages/ui-components/src/__tests__/SelectToken.test.ts @@ -1,4 +1,5 @@ -import { render, fireEvent } from '@testing-library/svelte'; +import { render, waitFor } from '@testing-library/svelte'; +import userEvent from '@testing-library/user-event'; import { describe, it, expect, vi, beforeEach } from 'vitest'; import SelectToken from '../lib/components/deployment/SelectToken.svelte'; import type { ComponentProps } from 'svelte'; @@ -8,13 +9,17 @@ export type SelectTokenComponentProps = ComponentProps; describe('SelectToken', () => { const mockGui: DotrainOrderGui = { saveSelectTokenAddress: vi.fn().mockResolvedValue(undefined), - getSelectTokens: vi.fn().mockReturnValue(new Map([['TOKEN1', '0x123']])) + getSelectTokens: vi.fn().mockReturnValue(new Map([['TOKEN1', '0x123']])), + getTokenInfos: vi.fn().mockResolvedValue(new Map([ + ['0x123', { name: 'Test Token', symbol: 'TEST', decimals: 18 }] + ])) } as unknown as DotrainOrderGui; const mockProps: SelectTokenComponentProps = { - token: 'TOKEN1', + token: ['TOKEN1', '0x123'], gui: mockGui, - selectTokens: new Map([['TOKEN1', '0x123']]) + selectTokens: new Map([['TOKEN1', '0x123']]), + tokenInfos: new Map([['0x123', { name: 'Test Token', symbol: 'TEST', decimals: 18 }]]) }; beforeEach(() => { @@ -31,26 +36,54 @@ describe('SelectToken', () => { expect(getByRole('textbox')).toBeInTheDocument(); }); - it('calls saveSelectTokenAddress when input changes', async () => { + it('calls saveSelectTokenAddress and updates token info when input changes', async () => { + const user = userEvent.setup(); const { getByRole } = render(SelectToken, mockProps); const input = getByRole('textbox'); - await fireEvent.change(input, { target: { value: '0x456' } }); + await user.clear(input); + await user.type(input, '0x456'); - expect(mockGui.saveSelectTokenAddress).toHaveBeenCalledWith('TOKEN1', '0x456'); - expect(mockGui.getSelectTokens).toHaveBeenCalled(); + await waitFor(() => { + expect(mockGui.saveSelectTokenAddress).toHaveBeenCalledWith('TOKEN1', '0x456'); + expect(mockGui.getSelectTokens).toHaveBeenCalled(); + expect(mockGui.getTokenInfos).toHaveBeenCalled(); + }); + }); + + it('shows error message for invalid address', async () => { + const user = userEvent.setup(); + const mockGuiWithError = { + ...mockGui, + saveSelectTokenAddress: vi.fn().mockRejectedValue(new Error('Invalid address')) + } as unknown as DotrainOrderGui; + + const { getByRole, findByText } = render(SelectToken, { + ...mockProps, + gui: mockGuiWithError + }); + + const input = getByRole('textbox'); + await user.type(input, 'invalid'); + + await waitFor(() => { + expect(findByText('Invalid address')).resolves.toBeInTheDocument(); + }); }); it('does nothing if gui is not defined', async () => { + const user = userEvent.setup(); const { getByRole } = render(SelectToken, { ...mockProps, gui: undefined } as unknown as SelectTokenComponentProps); const input = getByRole('textbox'); - await fireEvent.change(input, { target: { value: '0x456' } }); + await user.type(input, '0x456'); - expect(mockGui.saveSelectTokenAddress).not.toHaveBeenCalled(); - expect(mockGui.getSelectTokens).not.toHaveBeenCalled(); + await waitFor(() => { + expect(mockGui.saveSelectTokenAddress).not.toHaveBeenCalled(); + expect(mockGui.getSelectTokens).not.toHaveBeenCalled(); + }); }); }); diff --git a/packages/ui-components/src/lib/components/deployment/DeploymentSteps.svelte b/packages/ui-components/src/lib/components/deployment/DeploymentSteps.svelte index b0e6376fe..469b508ff 100644 --- a/packages/ui-components/src/lib/components/deployment/DeploymentSteps.svelte +++ b/packages/ui-components/src/lib/components/deployment/DeploymentSteps.svelte @@ -283,8 +283,8 @@ {#if selectTokens} - {#each selectTokens.entries() as [token]} - + {#each selectTokens.entries() as token} + {/each} {/if} diff --git a/packages/ui-components/src/lib/components/deployment/SelectToken.svelte b/packages/ui-components/src/lib/components/deployment/SelectToken.svelte index 9acb117c9..4dd79ff58 100644 --- a/packages/ui-components/src/lib/components/deployment/SelectToken.svelte +++ b/packages/ui-components/src/lib/components/deployment/SelectToken.svelte @@ -1,33 +1,64 @@ + let checking = false; -
- - { - if (currentTarget instanceof HTMLInputElement) { - if (!gui) return; - try { - await gui.saveSelectTokenAddress(token, currentTarget.value); - error = ''; - selectTokens = gui.getSelectTokens(); - gui = gui; - } catch { - error = 'Invalid address'; - } + async function handleInput(event: Event) { + checking = true; + tokenInfo = null; + const currentTarget = event.currentTarget; + if (currentTarget instanceof HTMLInputElement) { + inputValue = currentTarget.value; + if (!gui) return; + try { + await gui.saveSelectTokenAddress(token[0], currentTarget.value); + error = ''; + selectTokens = gui.getSelectTokens(); + gui = gui; + tokenInfos = await gui.getTokenInfos(); + tokenInfo = tokenInfos.get(token[1]) || null; + checking = false; + } catch { + checking = false; + error = 'Invalid address'; } - }} - /> - {#if error} -

{error}

+ } + } + + $: if (token && !inputValue && inputValue !== '') { + inputValue = token[1] || ''; + } + + +
+
+ + +
+ {#if checking} +
+ + Checking... +
+ {:else if tokenInfo} +
+ + {tokenInfo.name} +
+ {:else if error} +
+ + {error} +
{/if}
From 1e98b26f3176b7a49f99a1113405dad4667144c3 Mon Sep 17 00:00:00 2001 From: findolor Date: Fri, 10 Jan 2025 21:11:11 +0100 Subject: [PATCH 053/142] return empty map on missing select tokens and add method to clear select token --- crates/js_api/src/gui/select_tokens.rs | 35 +++++++++++++++------- packages/orderbook/test/js_api/gui.test.ts | 32 +++++++++++++++++++- 2 files changed, 55 insertions(+), 12 deletions(-) diff --git a/crates/js_api/src/gui/select_tokens.rs b/crates/js_api/src/gui/select_tokens.rs index 005662b5d..51f501f9b 100644 --- a/crates/js_api/src/gui/select_tokens.rs +++ b/crates/js_api/src/gui/select_tokens.rs @@ -21,20 +21,22 @@ impl DotrainOrderGui { /// Get all selected tokens and their addresses /// - /// Returns a map of token name to address + /// Returns a map of token key to address #[wasm_bindgen(js_name = "getSelectTokens")] pub fn get_select_tokens(&self) -> Result { - let select_tokens = self - .select_tokens - .clone() - .ok_or(GuiError::SelectTokensNotSet)?; - Ok(SelectTokens(select_tokens)) + let gui = self.get_current_deployment()?; + + if gui.select_tokens.is_none() || self.select_tokens.is_none() { + return Ok(SelectTokens(BTreeMap::new())); + } + + Ok(SelectTokens(self.select_tokens.clone().unwrap())) } #[wasm_bindgen(js_name = "saveSelectTokenAddress")] pub async fn save_select_token_address( &mut self, - token_name: String, + key: String, address: String, ) -> Result<(), GuiError> { let deployment = self.get_current_deployment()?; @@ -42,12 +44,12 @@ impl DotrainOrderGui { .select_tokens .clone() .ok_or(GuiError::SelectTokensNotSet)?; - if !select_tokens.contains_key(&token_name) { - return Err(GuiError::TokenNotFound(token_name.clone())); + if !select_tokens.contains_key(&key) { + return Err(GuiError::TokenNotFound(key.clone())); } let address = Address::from_str(&address)?; - select_tokens.insert(token_name.clone(), address); + select_tokens.insert(key.clone(), address); self.select_tokens = Some(select_tokens); let rpc_url = deployment @@ -65,8 +67,19 @@ impl DotrainOrderGui { self.dotrain_order .orderbook_yaml() - .get_token(&token_name)? + .get_token(&key)? .update_address(&address.to_string())?; Ok(()) } + + #[wasm_bindgen(js_name = "clearSelectTokenAddress")] + pub fn clear_select_token_address(&mut self, key: String) -> Result<(), GuiError> { + let mut select_tokens = self + .select_tokens + .clone() + .ok_or(GuiError::SelectTokensNotSet)?; + select_tokens.insert(key.clone(), Address::ZERO); + self.select_tokens = Some(select_tokens); + Ok(()) + } } diff --git a/packages/orderbook/test/js_api/gui.test.ts b/packages/orderbook/test/js_api/gui.test.ts index 880f138c8..1eb5ac5c6 100644 --- a/packages/orderbook/test/js_api/gui.test.ts +++ b/packages/orderbook/test/js_api/gui.test.ts @@ -983,7 +983,7 @@ describe('Rain Orderbook JS API Package Bindgen Tests - Gui', async function () ); let testGui = await DotrainOrderGui.chooseDeployment(dotrainWithGui, 'some-deployment'); - expect(() => testGui.getSelectTokens()).toThrow('Select tokens not set'); + assert.equal(testGui.getSelectTokens().size, 0); await expect( async () => await testGui.saveSelectTokenAddress('token1', '0x1') ).rejects.toThrow('Select tokens not set'); @@ -1049,5 +1049,35 @@ describe('Rain Orderbook JS API Package Bindgen Tests - Gui', async function () '0x8888888888888888888888888888888888888888' ); }); + + it('should clear select token address to fallback value', async () => { + mockServer + .forPost('/rpc-url') + .once() + .withBodyIncluding('0x82ad56cb') + .thenSendJsonRpcResult( + '0x00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000001a0000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000007546f6b656e203100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000025431000000000000000000000000000000000000000000000000000000000000' + ); + // token2 info + mockServer + .forPost('/rpc-url') + .once() + .withBodyIncluding('0x82ad56cb') + .thenSendJsonRpcResult( + '0x00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000e000000000000000000000000000000000000000000000000000000000000001a000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000754656b656e203200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000025432000000000000000000000000000000000000000000000000000000000000' + ); + + await gui.saveSelectTokenAddress('token1', '0x6666666666666666666666666666666666666666'); + assert.equal( + gui.getSelectTokens().get('token1'), + '0x6666666666666666666666666666666666666666' + ); + + gui.clearSelectTokenAddress('token1'); + assert.equal( + gui.getSelectTokens().get('token1'), + '0x0000000000000000000000000000000000000000' + ); + }); }); }); From 4ae91c66e4fcf890f1198f71d7cb1d78cdb3c463 Mon Sep 17 00:00:00 2001 From: Jamie Harding Date: Mon, 13 Jan 2025 07:34:05 +0100 Subject: [PATCH 054/142] format --- packages/ui-components/src/__tests__/SelectToken.test.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/ui-components/src/__tests__/SelectToken.test.ts b/packages/ui-components/src/__tests__/SelectToken.test.ts index 444a649a7..9ed231d71 100644 --- a/packages/ui-components/src/__tests__/SelectToken.test.ts +++ b/packages/ui-components/src/__tests__/SelectToken.test.ts @@ -10,9 +10,9 @@ describe('SelectToken', () => { const mockGui: DotrainOrderGui = { saveSelectTokenAddress: vi.fn().mockResolvedValue(undefined), getSelectTokens: vi.fn().mockReturnValue(new Map([['TOKEN1', '0x123']])), - getTokenInfos: vi.fn().mockResolvedValue(new Map([ - ['0x123', { name: 'Test Token', symbol: 'TEST', decimals: 18 }] - ])) + getTokenInfos: vi + .fn() + .mockResolvedValue(new Map([['0x123', { name: 'Test Token', symbol: 'TEST', decimals: 18 }]])) } as unknown as DotrainOrderGui; const mockProps: SelectTokenComponentProps = { From ba6ad5447c990a2664e42395637141d20c63185d Mon Sep 17 00:00:00 2001 From: Jamie Harding Date: Mon, 13 Jan 2025 08:34:04 +0100 Subject: [PATCH 055/142] stage --- .../src/lib/components/IconTelegram.svelte | 13 ++++------- .../lib/components/BadgeExternalLink.svelte | 23 ------------------- 2 files changed, 5 insertions(+), 31 deletions(-) delete mode 100644 tauri-app/src/lib/components/BadgeExternalLink.svelte diff --git a/packages/ui-components/src/lib/components/IconTelegram.svelte b/packages/ui-components/src/lib/components/IconTelegram.svelte index f11392093..cfac15c3c 100644 --- a/packages/ui-components/src/lib/components/IconTelegram.svelte +++ b/packages/ui-components/src/lib/components/IconTelegram.svelte @@ -1,15 +1,12 @@ - - diff --git a/tauri-app/src/lib/components/BadgeExternalLink.svelte b/tauri-app/src/lib/components/BadgeExternalLink.svelte deleted file mode 100644 index f8e20f105..000000000 --- a/tauri-app/src/lib/components/BadgeExternalLink.svelte +++ /dev/null @@ -1,23 +0,0 @@ - - - - - {text} - From 18c27ebab0947318f61fb07ec0a3ce8319a6a233 Mon Sep 17 00:00:00 2001 From: Jamie Harding Date: Mon, 13 Jan 2025 08:35:52 +0100 Subject: [PATCH 056/142] rm --- .../lib/components/BadgeExternalLink.svelte | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 tauri-app/src/lib/components/BadgeExternalLink.svelte diff --git a/tauri-app/src/lib/components/BadgeExternalLink.svelte b/tauri-app/src/lib/components/BadgeExternalLink.svelte new file mode 100644 index 000000000..f8e20f105 --- /dev/null +++ b/tauri-app/src/lib/components/BadgeExternalLink.svelte @@ -0,0 +1,23 @@ + + + + + {text} + From e18a379b0d25779731d1376e197d995ef31330a0 Mon Sep 17 00:00:00 2001 From: Jamie Harding Date: Mon, 13 Jan 2025 09:06:01 +0100 Subject: [PATCH 057/142] add tele icon --- packages/webapp/src/routes/test/+page.svelte | 2 +- tauri-app/src/routes/+page.svelte | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/webapp/src/routes/test/+page.svelte b/packages/webapp/src/routes/test/+page.svelte index e56869beb..f42a0153d 100644 --- a/packages/webapp/src/routes/test/+page.svelte +++ b/packages/webapp/src/routes/test/+page.svelte @@ -30,7 +30,7 @@ - +
@@ -152,7 +164,10 @@ tauri-app/src/lib/components/detail/VaultDetail.svelte goto(`/orders/${order.id}`)} + on:click={() => { + updateActiveNetworkAndOrderbook(order.subgraphName); + goto(`/orders/${order.id}`); + }} > From b2a11f01aececd5cf50fb53654e5b5f59e3c40cd Mon Sep 17 00:00:00 2001 From: Jamie Harding Date: Mon, 13 Jan 2025 10:31:43 +0100 Subject: [PATCH 061/142] move vaultDetail into component --- .../routes/vaults/[network]-[id]/+page.svelte | 137 ++---------------- 1 file changed, 13 insertions(+), 124 deletions(-) diff --git a/packages/webapp/src/routes/vaults/[network]-[id]/+page.svelte b/packages/webapp/src/routes/vaults/[network]-[id]/+page.svelte index c95db0889..157c57acc 100644 --- a/packages/webapp/src/routes/vaults/[network]-[id]/+page.svelte +++ b/packages/webapp/src/routes/vaults/[network]-[id]/+page.svelte @@ -1,130 +1,19 @@ - - -
- {data.token.name} -
-
- - - Vault ID - {bigintStringToHex(data.vaultId)} - - - - Orderbook - - - - - - - Owner Address - - - - - - - Token address - - - - - - - Balance - {formatUnits(BigInt(data.balance), Number(data.token.decimals ?? 0))} - {data.token.symbol} - - - - Orders as input - -

- {#if data.ordersAsInput && data.ordersAsInput.length > 0} - {#each data.ordersAsInput as order} - - {/each} - {:else} - None - {/if} -

-
-
- - - Orders as output - -

- {#if data.ordersAsOutput && data.ordersAsOutput.length > 0} - {#each data.ordersAsOutput as order} - - {/each} - {:else} - None - {/if} -

-
-
-
- - - - + - -
+ From 4915c7dec394d2e417188b3edcc1311246cc5d64 Mon Sep 17 00:00:00 2001 From: Jamie Harding Date: Mon, 13 Jan 2025 11:15:23 +0100 Subject: [PATCH 062/142] add refs to props --- .../src/__tests__/VaultDetail.test.ts | 14 ++++++++++---- .../src/routes/vaults/[network]-[id]/+page.svelte | 4 +++- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/packages/ui-components/src/__tests__/VaultDetail.test.ts b/packages/ui-components/src/__tests__/VaultDetail.test.ts index 3a104c195..1dd3538d0 100644 --- a/packages/ui-components/src/__tests__/VaultDetail.test.ts +++ b/packages/ui-components/src/__tests__/VaultDetail.test.ts @@ -3,7 +3,7 @@ import { test, vi } from 'vitest'; import { expect } from '$lib/test/matchers'; import { QueryClient } from '@tanstack/svelte-query'; import VaultDetail from '../lib/components/detail/VaultDetail.svelte'; -import { readable } from 'svelte/store'; +import { readable, writable } from 'svelte/store'; import { darkChartTheme } from '../lib/utils/lightweightChartsThemes'; // Mock the js_api getVault function @@ -37,7 +37,9 @@ test('calls the vault detail query fn with the correct vault id', async () => { id: '100', network: 'mainnet', settings: mockSettings, - lightweightChartsTheme: readable(darkChartTheme) + lightweightChartsTheme: readable(darkChartTheme), + activeNetworkRef: writable('mainnet'), + activeOrderbookRef: writable('0x00') }, context: new Map([['$$_queryClient', queryClient]]) }); @@ -56,7 +58,9 @@ test('shows the correct empty message when the query returns no data', async () id: '100', network: 'mainnet', settings: mockSettings, - lightweightChartsTheme: readable(darkChartTheme) + lightweightChartsTheme: readable(darkChartTheme), + activeNetworkRef: writable('mainnet'), + activeOrderbookRef: writable('0x00') }, context: new Map([['$$_queryClient', queryClient]]) }); @@ -97,7 +101,9 @@ test('shows the correct data when the query returns data', async () => { id: '100', network: 'mainnet', settings: mockSettings, - lightweightChartsTheme: readable(darkChartTheme) + lightweightChartsTheme: readable(darkChartTheme), + activeNetworkRef: writable('mainnet'), + activeOrderbookRef: writable('0x00') }, context: new Map([['$$_queryClient', queryClient]]) }); diff --git a/tauri-app/src/routes/vaults/[network]-[id]/+page.svelte b/tauri-app/src/routes/vaults/[network]-[id]/+page.svelte index 49e788551..efbf8b951 100644 --- a/tauri-app/src/routes/vaults/[network]-[id]/+page.svelte +++ b/tauri-app/src/routes/vaults/[network]-[id]/+page.svelte @@ -3,7 +3,7 @@ import { PageHeader } from '@rainlanguage/ui-components'; import { page } from '$app/stores'; import { VaultDetail } from '@rainlanguage/ui-components'; - import { settings } from '$lib/stores/settings'; + import { settings, activeNetworkRef, activeOrderbookRef } from '$lib/stores/settings'; import { lightweightChartsTheme } from '$lib/stores/darkMode'; import { handleDepositModal, handleWithdrawModal } from '$lib/services/modal'; @@ -18,4 +18,6 @@ {lightweightChartsTheme} {settings} {walletAddressMatchesOrBlank} + {activeNetworkRef} + {activeOrderbookRef} /> From 09feb680dc28f65fce0285a54e521ca5fa978221 Mon Sep 17 00:00:00 2001 From: Jamie Harding Date: Mon, 13 Jan 2025 11:43:41 +0100 Subject: [PATCH 063/142] format --- .../ui-components/src/lib/components/detail/VaultDetail.svelte | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/ui-components/src/lib/components/detail/VaultDetail.svelte b/packages/ui-components/src/lib/components/detail/VaultDetail.svelte index 04354eb29..8b321af98 100644 --- a/packages/ui-components/src/lib/components/detail/VaultDetail.svelte +++ b/packages/ui-components/src/lib/components/detail/VaultDetail.svelte @@ -21,7 +21,6 @@ import type { Vault } from '@rainlanguage/orderbook/js_api'; import type { AppStoresInterface } from '../../types/appStores'; - export let id: string; export let network: string; export let walletAddressMatchesOrBlank: Readable<(otherAddress: string) => boolean> | undefined = From 2ea00202c43711eca9b0bf90e06d918476a1e259 Mon Sep 17 00:00:00 2001 From: Jamie Harding Date: Mon, 13 Jan 2025 12:32:54 +0100 Subject: [PATCH 064/142] fix scenarrio --- .../lib/components/deployment/test-strategy-token-select.rain | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/ui-components/src/lib/components/deployment/test-strategy-token-select.rain b/packages/ui-components/src/lib/components/deployment/test-strategy-token-select.rain index c0d4aef91..7d3d8a00b 100644 --- a/packages/ui-components/src/lib/components/deployment/test-strategy-token-select.rain +++ b/packages/ui-components/src/lib/components/deployment/test-strategy-token-select.rain @@ -35,6 +35,7 @@ orders: - token: token2 scenarios: flare: + deployer: flare orderbook: flare runs: 1 bindings: From 389571012ef1a3a8bec53a3d4319165f77310a9e Mon Sep 17 00:00:00 2001 From: findolor Date: Mon, 13 Jan 2025 13:28:17 +0100 Subject: [PATCH 065/142] add token add/remove functions for yaml string --- crates/settings/src/token.rs | 97 +++++++++++++++++++++++++++ crates/settings/src/yaml/orderbook.rs | 42 ++++++++++++ 2 files changed, 139 insertions(+) diff --git a/crates/settings/src/token.rs b/crates/settings/src/token.rs index b9a180653..62e307cf7 100644 --- a/crates/settings/src/token.rs +++ b/crates/settings/src/token.rs @@ -7,6 +7,7 @@ use serde::{Deserialize, Serialize}; use std::str::FromStr; use std::sync::RwLock; use std::{collections::HashMap, sync::Arc}; +use strict_yaml_rust::strict_yaml::Hash; use strict_yaml_rust::StrictYaml; use thiserror::Error; use typeshare::typeshare; @@ -74,6 +75,102 @@ impl Token { Ok(self.clone()) } + + pub fn add_record_to_yaml( + documents: Vec>>, + key: &str, + network_key: &str, + address: &str, + decimals: Option<&str>, + label: Option<&str>, + symbol: Option<&str>, + ) -> Result<(), YamlError> { + let address = Token::validate_address(address)?; + let decimals = decimals.map(|d| Token::validate_decimals(d)).transpose()?; + Network::parse_from_yaml(documents.clone(), network_key)?; + + let mut document = documents[0] + .write() + .map_err(|_| YamlError::WriteLockError)?; + + if let StrictYaml::Hash(ref mut document_hash) = *document { + if !document_hash.contains_key(&StrictYaml::String("tokens".to_string())) { + document_hash.insert( + StrictYaml::String("tokens".to_string()), + StrictYaml::Hash(Hash::new()), + ); + } + + if let Some(StrictYaml::Hash(ref mut tokens)) = + document_hash.get_mut(&StrictYaml::String("tokens".to_string())) + { + if tokens.contains_key(&StrictYaml::String(key.to_string())) { + return Err(YamlError::KeyShadowing(key.to_string())); + } + + let mut token_hash = Hash::new(); + token_hash.insert( + StrictYaml::String("network".to_string()), + StrictYaml::String(network_key.to_string()), + ); + token_hash.insert( + StrictYaml::String("address".to_string()), + StrictYaml::String(address.to_string()), + ); + if let Some(decimals) = decimals { + token_hash.insert( + StrictYaml::String("decimals".to_string()), + StrictYaml::String(decimals.to_string()), + ); + } + if let Some(label) = label { + token_hash.insert( + StrictYaml::String("label".to_string()), + StrictYaml::String(label.to_string()), + ); + } + if let Some(symbol) = symbol { + token_hash.insert( + StrictYaml::String("symbol".to_string()), + StrictYaml::String(symbol.to_string()), + ); + } + + tokens.insert( + StrictYaml::String(key.to_string()), + StrictYaml::Hash(token_hash), + ); + } else { + return Err(YamlError::ParseError("missing field: tokens".to_string())); + } + } else { + return Err(YamlError::ParseError("document parse error".to_string())); + } + + Ok(()) + } + + pub fn remove_record_from_yaml( + documents: Vec>>, + key: &str, + ) -> Result<(), YamlError> { + for document in documents { + let mut document_write = document.write().map_err(|_| YamlError::WriteLockError)?; + + if let StrictYaml::Hash(ref mut document_hash) = *document_write { + if let Some(StrictYaml::Hash(ref mut tokens)) = + document_hash.get_mut(&StrictYaml::String("tokens".to_string())) + { + if tokens.contains_key(&StrictYaml::String(key.to_string())) { + tokens.remove(&StrictYaml::String(key.to_string())); + return Ok(()); + } + } + } + } + + Err(YamlError::KeyNotFound(key.to_string())) + } } impl YamlParsableHash for Token { fn parse_all_from_yaml( diff --git a/crates/settings/src/yaml/orderbook.rs b/crates/settings/src/yaml/orderbook.rs index 60445bafe..ea88bb7f3 100644 --- a/crates/settings/src/yaml/orderbook.rs +++ b/crates/settings/src/yaml/orderbook.rs @@ -355,6 +355,48 @@ mod tests { ); } + #[test] + fn test_add_token_to_yaml() { + let yaml = r#" +networks: + mainnet: + rpc: "https://mainnet.infura.io" + chain-id: "1" +"#; + let ob_yaml = OrderbookYaml::new(vec![yaml.to_string()], false).unwrap(); + + Token::add_record_to_yaml( + ob_yaml.documents.clone(), + "test-token", + "mainnet", + "0x0000000000000000000000000000000000000001", + Some("18"), + Some("Test Token"), + Some("TTK"), + ) + .unwrap(); + + let token = ob_yaml.get_token("test-token").unwrap(); + assert_eq!(token.key, "test-token"); + assert_eq!(token.network.key, "mainnet"); + assert_eq!( + token.address, + Address::from_str("0x0000000000000000000000000000000000000001").unwrap() + ); + assert_eq!(token.decimals, Some(18)); + assert_eq!(token.label, Some("Test Token".to_string())); + assert_eq!(token.symbol, Some("TTK".to_string())); + } + + #[test] + fn test_remove_token_from_yaml() { + let ob_yaml = OrderbookYaml::new(vec![FULL_YAML.to_string()], false).unwrap(); + + assert!(ob_yaml.get_token("token1").is_ok()); + Token::remove_record_from_yaml(ob_yaml.documents.clone(), "token1").unwrap(); + assert!(ob_yaml.get_token("token1").is_err()); + } + #[test] fn test_add_metaboard_to_yaml() { let yaml = r#" From ac0bbdc962927f61285c06ea21407692fdcd7374 Mon Sep 17 00:00:00 2001 From: findolor Date: Mon, 13 Jan 2025 14:53:33 +0100 Subject: [PATCH 066/142] move erc20 query to get_token_info function --- crates/js_api/src/gui/mod.rs | 89 +++++++++++++++--------------------- 1 file changed, 37 insertions(+), 52 deletions(-) diff --git a/crates/js_api/src/gui/mod.rs b/crates/js_api/src/gui/mod.rs index 8bfb86cc1..6124f2fc4 100644 --- a/crates/js_api/src/gui/mod.rs +++ b/crates/js_api/src/gui/mod.rs @@ -26,10 +26,6 @@ mod state_management; pub struct AvailableDeployments(Vec); impl_all_wasm_traits!(AvailableDeployments); -#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Tsify)] -pub struct TokenInfos(#[tsify(type = "Map")] BTreeMap); -impl_all_wasm_traits!(TokenInfos); - #[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] #[wasm_bindgen] pub struct DotrainOrderGui { @@ -37,8 +33,6 @@ pub struct DotrainOrderGui { selected_deployment: String, field_values: BTreeMap, deposits: BTreeMap, - select_tokens: Option>, - onchain_token_info: BTreeMap, } #[wasm_bindgen] impl DotrainOrderGui { @@ -60,7 +54,6 @@ impl DotrainOrderGui { pub async fn choose_deployment( dotrain: String, deployment_name: String, - multicall_address: Option, ) -> Result { let dotrain_order = DotrainOrder::new(dotrain, None).await?; @@ -68,44 +61,8 @@ impl DotrainOrderGui { .dotrain_yaml() .get_gui()? .ok_or(GuiError::GuiConfigNotFound)?; - - let (_, gui_deployment) = gui - .deployments - .into_iter() - .find(|(name, _)| name == &deployment_name) - .ok_or(GuiError::DeploymentNotFound(deployment_name.clone()))?; - - let select_tokens = gui_deployment.select_tokens.clone().map(|tokens| { - tokens - .iter() - .map(|token: &String| (token.clone(), Address::ZERO)) - .collect::>() - }); - - let rpc_url = gui_deployment - .deployment - .order - .orderbook - .clone() - .ok_or(GuiError::OrderbookNotFound)? - .network - .rpc - .clone(); - let mut onchain_token_info: BTreeMap = BTreeMap::new(); - for token in gui_deployment.deposits.iter() { - if onchain_token_info.contains_key(&token.token.address) { - continue; - } - - if let Some(select_tokens) = &select_tokens { - if select_tokens.contains_key(&token.token.key) { - continue; - } - } - - let erc20 = ERC20::new(rpc_url.clone(), token.token.address); - let token_info = erc20.token_info(multicall_address.clone()).await?; - onchain_token_info.insert(token.token.address, token_info); + if !gui.deployments.contains_key(&deployment_name) { + return Err(GuiError::DeploymentNotFound(deployment_name.clone())); } Ok(Self { @@ -113,8 +70,6 @@ impl DotrainOrderGui { selected_deployment: deployment_name.clone(), field_values: BTreeMap::new(), deposits: BTreeMap::new(), - select_tokens, - onchain_token_info, }) } @@ -141,12 +96,42 @@ impl DotrainOrderGui { Ok(gui_deployment.clone()) } - /// Get all token infos in input and output vaults + /// Get token info for a given key /// - /// Returns a map of token address to [`TokenInfo`] - #[wasm_bindgen(js_name = "getTokenInfos")] - pub fn get_token_infos(&self) -> Result { - Ok(TokenInfos(self.onchain_token_info.clone())) + /// Returns a [`TokenInfo`] + #[wasm_bindgen(js_name = "getTokenInfo")] + pub async fn get_token_info(&self, key: String) -> Result { + let deployment = self.get_current_deployment()?; + let token = self.dotrain_order.orderbook_yaml().get_token(&key)?; + + let token_info = + if token.decimals.is_some() && token.label.is_some() && token.symbol.is_some() { + TokenInfo { + decimals: token.decimals.unwrap(), + name: token.label.unwrap(), + symbol: token.symbol.unwrap(), + } + } else { + let rpc_url = deployment + .deployment + .order + .orderbook + .clone() + .ok_or(GuiError::OrderbookNotFound)? + .network + .rpc + .clone(); + let erc20 = ERC20::new(rpc_url, token.address); + let onchain_info = erc20.token_info(None).await?; + + TokenInfo { + decimals: token.decimals.unwrap_or(onchain_info.decimals), + name: token.label.unwrap_or(onchain_info.name), + symbol: token.symbol.unwrap_or(onchain_info.symbol), + } + }; + + Ok(token_info) } } From 97e22a26d5dc1a55a48cb9f5e79eed5abebeb598 Mon Sep 17 00:00:00 2001 From: findolor Date: Mon, 13 Jan 2025 14:53:54 +0100 Subject: [PATCH 067/142] refator select tokens functionality --- crates/js_api/src/gui/select_tokens.rs | 96 ++++++++++++++------------ 1 file changed, 50 insertions(+), 46 deletions(-) diff --git a/crates/js_api/src/gui/select_tokens.rs b/crates/js_api/src/gui/select_tokens.rs index 51f501f9b..6bb011a9b 100644 --- a/crates/js_api/src/gui/select_tokens.rs +++ b/crates/js_api/src/gui/select_tokens.rs @@ -1,56 +1,52 @@ -use std::str::FromStr; - use super::*; - -#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Tsify)] -pub struct SelectTokens(#[tsify(type = "Map")] BTreeMap); -impl_all_wasm_traits!(SelectTokens); +use rain_orderbook_app_settings::token::Token; +use std::str::FromStr; #[wasm_bindgen] impl DotrainOrderGui { - pub fn check_token_addresses(&self) -> Result<(), GuiError> { - if let Some(select_tokens) = &self.select_tokens { - for (token, address) in select_tokens.iter() { - if address == &Address::ZERO { - return Err(GuiError::TokenMustBeSelected(token.clone())); - } - } - } - Ok(()) + #[wasm_bindgen(js_name = "getSelectTokens")] + pub fn get_select_tokens(&self) -> Result, GuiError> { + let deployment = self.get_current_deployment()?; + Ok(deployment.select_tokens.unwrap_or(vec![])) } - /// Get all selected tokens and their addresses - /// - /// Returns a map of token key to address - #[wasm_bindgen(js_name = "getSelectTokens")] - pub fn get_select_tokens(&self) -> Result { - let gui = self.get_current_deployment()?; + #[wasm_bindgen(js_name = "isSelectTokenSet")] + pub fn is_select_token_set(&self, key: String) -> Result { + Ok(self.dotrain_order.orderbook_yaml().get_token(&key).is_ok()) + } - if gui.select_tokens.is_none() || self.select_tokens.is_none() { - return Ok(SelectTokens(BTreeMap::new())); + #[wasm_bindgen(js_name = "checkSelectTokens")] + pub fn check_select_tokens(&self) -> Result<(), GuiError> { + let deployment = self.get_current_deployment()?; + + if let Some(select_tokens) = deployment.select_tokens { + for key in select_tokens { + self.dotrain_order + .orderbook_yaml() + .get_token(&key) + .map_err(|_| GuiError::SelectTokensNotSet)?; + } } - Ok(SelectTokens(self.select_tokens.clone().unwrap())) + Ok(()) } - #[wasm_bindgen(js_name = "saveSelectTokenAddress")] - pub async fn save_select_token_address( + #[wasm_bindgen(js_name = "saveSelectToken")] + pub async fn save_select_token( &mut self, key: String, address: String, ) -> Result<(), GuiError> { let deployment = self.get_current_deployment()?; - let mut select_tokens = self - .select_tokens - .clone() - .ok_or(GuiError::SelectTokensNotSet)?; - if !select_tokens.contains_key(&key) { + if deployment.select_tokens.is_none() { + return Err(GuiError::SelectTokensNotSet); + } + let select_tokens = deployment.select_tokens.unwrap(); + if !select_tokens.contains(&key) { return Err(GuiError::TokenNotFound(key.clone())); } let address = Address::from_str(&address)?; - select_tokens.insert(key.clone(), address); - self.select_tokens = Some(select_tokens); let rpc_url = deployment .deployment @@ -63,23 +59,31 @@ impl DotrainOrderGui { .clone(); let erc20 = ERC20::new(rpc_url.clone(), address); let token_info = erc20.token_info(None).await?; - self.onchain_token_info.insert(address, token_info); - self.dotrain_order - .orderbook_yaml() - .get_token(&key)? - .update_address(&address.to_string())?; + Token::add_record_to_yaml( + self.dotrain_order.orderbook_yaml().documents, + &key, + &deployment.deployment.scenario.deployer.network.key, + &address.to_string(), + Some(&token_info.decimals.to_string()), + Some(&token_info.name), + Some(&token_info.symbol), + )?; Ok(()) } - #[wasm_bindgen(js_name = "clearSelectTokenAddress")] - pub fn clear_select_token_address(&mut self, key: String) -> Result<(), GuiError> { - let mut select_tokens = self - .select_tokens - .clone() - .ok_or(GuiError::SelectTokensNotSet)?; - select_tokens.insert(key.clone(), Address::ZERO); - self.select_tokens = Some(select_tokens); + #[wasm_bindgen(js_name = "removeSelectToken")] + pub fn remove_select_token(&mut self, key: String) -> Result<(), GuiError> { + let deployment = self.get_current_deployment()?; + if deployment.select_tokens.is_none() { + return Err(GuiError::SelectTokensNotSet); + } + let select_tokens = deployment.select_tokens.unwrap(); + if !select_tokens.contains(&key) { + return Err(GuiError::TokenNotFound(key.clone())); + } + + Token::remove_record_from_yaml(self.dotrain_order.orderbook_yaml().documents, &key)?; Ok(()) } } From 62640d49651545af57a0ba7410e7c2df12f32045 Mon Sep 17 00:00:00 2001 From: findolor Date: Mon, 13 Jan 2025 14:54:32 +0100 Subject: [PATCH 068/142] refactor calldata related functions --- crates/common/src/dotrain_order/calldata.rs | 4 +- crates/js_api/src/gui/order_operations.rs | 46 +++++++++++---------- 2 files changed, 26 insertions(+), 24 deletions(-) diff --git a/crates/common/src/dotrain_order/calldata.rs b/crates/common/src/dotrain_order/calldata.rs index 19d755178..74bf36ef6 100644 --- a/crates/common/src/dotrain_order/calldata.rs +++ b/crates/common/src/dotrain_order/calldata.rs @@ -45,7 +45,7 @@ impl DotrainOrder { &self, deployment_name: &str, owner: &str, - token_deposits: &HashMap, + token_deposits: &HashMap, ) -> Result, DotrainOrderCalldataError> { let deployment = self.get_deployment(deployment_name)?; let orderbook = self.get_orderbook(deployment_name)?; @@ -53,7 +53,7 @@ impl DotrainOrder { let mut calldatas = Vec::new(); for output in &deployment.order.outputs { - if let Some(deposit_amount) = token_deposits.get(&output.token.address) { + if let Some(deposit_amount) = token_deposits.get(&output.token.key) { let deposit_amount = deposit_amount.to_owned(); let deposit_args = DepositArgs { token: output.token.address, diff --git a/crates/js_api/src/gui/order_operations.rs b/crates/js_api/src/gui/order_operations.rs index c5cfec09f..9670e6021 100644 --- a/crates/js_api/src/gui/order_operations.rs +++ b/crates/js_api/src/gui/order_operations.rs @@ -54,36 +54,32 @@ impl DotrainOrderGui { .cloned() } - fn get_deposits_as_map(&self) -> Result, GuiError> { - let mut map: HashMap = HashMap::new(); + async fn get_deposits_as_map(&self) -> Result, GuiError> { + let mut map: HashMap = HashMap::new(); for d in self.get_deposits()? { - let token_decimals = self - .onchain_token_info - .get(&d.address) - .ok_or(GuiError::TokenNotFound(d.address.to_string()))? - .decimals; - let amount = parse_units(&d.amount, token_decimals)?.into(); - map.insert(d.address, amount); + let token_info = self.get_token_info(d.token.clone()).await?; + let amount = parse_units(&d.amount, token_info.decimals)?.into(); + map.insert(d.token, amount); } Ok(map) } - fn get_vaults_and_deposits( + async fn get_vaults_and_deposits( &self, deployment: &GuiDeployment, ) -> Result, GuiError> { - let deposits_map = self.get_deposits_as_map()?; + let deposits_map = self.get_deposits_as_map().await?; let results = deployment .deployment .order .outputs .clone() .into_iter() - .filter(|output| deposits_map.contains_key(&output.token.address)) + .filter(|output| deposits_map.contains_key(&output.token.key)) .map(|output| { ( output.clone(), - *deposits_map.get(&output.token.address).unwrap(), + *deposits_map.get(&output.token.key).unwrap(), ) }) .collect(); @@ -118,10 +114,10 @@ impl DotrainOrderGui { #[wasm_bindgen(js_name = "checkAllowances")] pub async fn check_allowances(&self, owner: String) -> Result { let deployment = self.get_current_deployment()?; - self.check_token_addresses()?; + self.check_select_tokens()?; let orderbook = self.get_orderbook()?; - let vaults_and_deposits = self.get_vaults_and_deposits(&deployment)?; + let vaults_and_deposits = self.get_vaults_and_deposits(&deployment).await?; let mut results = Vec::new(); for (order_io, amount) in vaults_and_deposits.iter() { @@ -148,11 +144,15 @@ impl DotrainOrderGui { owner: String, ) -> Result { let deployment = self.get_current_deployment()?; - self.check_token_addresses()?; + self.check_select_tokens()?; let calldatas = self .dotrain_order - .generate_approval_calldatas(&deployment.key, &owner, &self.get_deposits_as_map()?) + .generate_approval_calldatas( + &deployment.key, + &owner, + &self.get_deposits_as_map().await?, + ) .await?; Ok(ApprovalCalldataResult(calldatas)) } @@ -187,11 +187,12 @@ impl DotrainOrderGui { #[wasm_bindgen(js_name = "generateDepositCalldatas")] pub async fn generate_deposit_calldatas(&mut self) -> Result { let deployment = self.get_current_deployment()?; - self.check_token_addresses()?; + self.check_select_tokens()?; self.populate_vault_ids(&deployment)?; let token_deposits = self - .get_vaults_and_deposits(&deployment)? + .get_vaults_and_deposits(&deployment) + .await? .iter() .enumerate() .map(|(i, (order_io, amount))| { @@ -214,7 +215,7 @@ impl DotrainOrderGui { &mut self, ) -> Result { let deployment = self.get_current_deployment()?; - self.check_token_addresses()?; + self.check_select_tokens()?; self.populate_vault_ids(&deployment)?; self.update_config_source_bindings(&deployment)?; @@ -230,12 +231,13 @@ impl DotrainOrderGui { &mut self, ) -> Result { let deployment = self.get_current_deployment()?; - self.check_token_addresses()?; + self.check_select_tokens()?; self.populate_vault_ids(&deployment)?; self.update_config_source_bindings(&deployment)?; let token_deposits = self - .get_vaults_and_deposits(&deployment)? + .get_vaults_and_deposits(&deployment) + .await? .iter() .enumerate() .map(|(i, (order_io, amount))| { From e28a1c17749e3c5ff6cf52ad5708cba3d54d5fc8 Mon Sep 17 00:00:00 2001 From: findolor Date: Mon, 13 Jan 2025 15:42:54 +0100 Subject: [PATCH 069/142] updae --- crates/js_api/src/gui/mod.rs | 13 ++++++++++++- crates/js_api/src/gui/select_tokens.rs | 7 +++---- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/crates/js_api/src/gui/mod.rs b/crates/js_api/src/gui/mod.rs index 6124f2fc4..6306896e0 100644 --- a/crates/js_api/src/gui/mod.rs +++ b/crates/js_api/src/gui/mod.rs @@ -9,7 +9,7 @@ use rain_orderbook_app_settings::{ use rain_orderbook_bindings::{impl_all_wasm_traits, wasm_traits::prelude::*}; use rain_orderbook_common::{ dotrain_order::{calldata::DotrainOrderCalldataError, DotrainOrder, DotrainOrderError}, - erc20::{TokenInfo, ERC20}, + erc20::ERC20, }; use serde::{Deserialize, Serialize}; use std::collections::BTreeMap; @@ -26,6 +26,15 @@ mod state_management; pub struct AvailableDeployments(Vec); impl_all_wasm_traits!(AvailableDeployments); +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Tsify)] +pub struct TokenInfo { + pub address: Address, + pub decimals: u8, + pub name: String, + pub symbol: String, +} +impl_all_wasm_traits!(TokenInfo); + #[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] #[wasm_bindgen] pub struct DotrainOrderGui { @@ -107,6 +116,7 @@ impl DotrainOrderGui { let token_info = if token.decimals.is_some() && token.label.is_some() && token.symbol.is_some() { TokenInfo { + address: token.address, decimals: token.decimals.unwrap(), name: token.label.unwrap(), symbol: token.symbol.unwrap(), @@ -125,6 +135,7 @@ impl DotrainOrderGui { let onchain_info = erc20.token_info(None).await?; TokenInfo { + address: token.address, decimals: token.decimals.unwrap_or(onchain_info.decimals), name: token.label.unwrap_or(onchain_info.name), symbol: token.symbol.unwrap_or(onchain_info.symbol), diff --git a/crates/js_api/src/gui/select_tokens.rs b/crates/js_api/src/gui/select_tokens.rs index 6bb011a9b..20ae160c4 100644 --- a/crates/js_api/src/gui/select_tokens.rs +++ b/crates/js_api/src/gui/select_tokens.rs @@ -21,10 +21,9 @@ impl DotrainOrderGui { if let Some(select_tokens) = deployment.select_tokens { for key in select_tokens { - self.dotrain_order - .orderbook_yaml() - .get_token(&key) - .map_err(|_| GuiError::SelectTokensNotSet)?; + if self.dotrain_order.orderbook_yaml().get_token(&key).is_err() { + return Err(GuiError::TokenMustBeSelected(key.clone())); + } } } From 87a22570a7c3e7359ef5e5ebd8d1266f6e6dcd3b Mon Sep 17 00:00:00 2001 From: findolor Date: Mon, 13 Jan 2025 16:29:29 +0100 Subject: [PATCH 070/142] make token field on gui and order optional --- crates/common/src/add_order.rs | 56 +++++++++------ crates/common/src/dotrain_order/calldata.rs | 30 +++++--- crates/settings/src/gui.rs | 35 +++------ crates/settings/src/order.rs | 80 +++++++++++---------- crates/settings/src/yaml/dotrain.rs | 13 ++-- 5 files changed, 117 insertions(+), 97 deletions(-) diff --git a/crates/common/src/add_order.rs b/crates/common/src/add_order.rs index 36eeaa3fa..32fd28b5e 100644 --- a/crates/common/src/add_order.rs +++ b/crates/common/src/add_order.rs @@ -60,6 +60,10 @@ pub enum AddOrderArgsError { #[cfg(not(target_family = "wasm"))] #[error(transparent)] ForkCallError(#[from] ForkCallError), + #[error("Input token not found for index: {0}")] + InputTokenNotFound(String), + #[error("Output token not found for index: {0}")] + OutputTokenNotFound(String), } #[derive(Debug, Serialize, Deserialize, Clone, PartialEq)] @@ -80,24 +84,29 @@ impl AddOrderArgs { ) -> Result { let random_vault_id: U256 = rand::random(); let mut inputs = vec![]; - for input in &deployment.order.inputs { - if let Some(decimals) = input.token.decimals { + for (i, input) in deployment.order.inputs.iter().enumerate() { + let input_token = input + .token + .as_ref() + .ok_or_else(|| AddOrderArgsError::InputTokenNotFound(i.to_string()))?; + + if let Some(decimals) = input_token.decimals { inputs.push(IO { - token: input.token.address, + token: input_token.address, vaultId: input.vault_id.unwrap_or(random_vault_id), decimals, }); } else { - let client = ReadableClientHttp::new_from_url(input.token.network.rpc.to_string())?; + let client = ReadableClientHttp::new_from_url(input_token.network.rpc.to_string())?; let parameters = ReadContractParameters { - address: input.token.address, + address: input_token.address, call: decimalsCall {}, block_number: None, gas: None, }; let decimals = client.read(parameters).await?._0; inputs.push(IO { - token: input.token.address, + token: input_token.address, vaultId: input.vault_id.unwrap_or(random_vault_id), decimals, }); @@ -105,25 +114,30 @@ impl AddOrderArgs { } let mut outputs = vec![]; - for output in &deployment.order.outputs { - if let Some(decimals) = output.token.decimals { + for (i, output) in deployment.order.outputs.iter().enumerate() { + let output_token = output + .token + .as_ref() + .ok_or_else(|| AddOrderArgsError::OutputTokenNotFound(i.to_string()))?; + + if let Some(decimals) = output_token.decimals { outputs.push(IO { - token: output.token.address, + token: output_token.address, vaultId: output.vault_id.unwrap_or(random_vault_id), decimals, }); } else { let client = - ReadableClientHttp::new_from_url(output.token.network.rpc.to_string())?; + ReadableClientHttp::new_from_url(output_token.network.rpc.to_string())?; let parameters = ReadContractParameters { - address: output.token.address, + address: output_token.address, call: decimalsCall {}, block_number: None, gas: None, }; let decimals = client.read(parameters).await?._0; outputs.push(IO { - token: output.token.address, + token: output_token.address, vaultId: output.vault_id.unwrap_or(random_vault_id), decimals, }); @@ -489,16 +503,16 @@ price: 2e18; key: "".to_string(), inputs: vec![ OrderIO { - token: token1_arc.clone(), + token: Some(token1_arc.clone()), vault_id: None, }, OrderIO { - token: token2_arc.clone(), + token: Some(token2_arc.clone()), vault_id: Some(known_vault_id), }, ], outputs: vec![OrderIO { - token: token3_arc.clone(), + token: Some(token3_arc.clone()), vault_id: None, }], network: network_arc.clone(), @@ -599,16 +613,16 @@ _ _: 0 0; key: "".to_string(), inputs: vec![ OrderIO { - token: token1_arc.clone(), + token: Some(token1_arc.clone()), vault_id: Some(U256::from(2)), }, OrderIO { - token: token2_arc.clone(), + token: Some(token2_arc.clone()), vault_id: Some(U256::from(1)), }, ], outputs: vec![OrderIO { - token: token3_arc.clone(), + token: Some(token3_arc.clone()), vault_id: Some(U256::from(4)), }], network: network_arc.clone(), @@ -745,16 +759,16 @@ _ _: 0 0; key: "".to_string(), inputs: vec![ OrderIO { - token: token1_arc.clone(), + token: Some(token1_arc.clone()), vault_id: None, }, OrderIO { - token: token2_arc.clone(), + token: Some(token2_arc.clone()), vault_id: Some(known_vault_id), }, ], outputs: vec![OrderIO { - token: token3_arc.clone(), + token: Some(token3_arc.clone()), vault_id: None, }], network: network_arc.clone(), diff --git a/crates/common/src/dotrain_order/calldata.rs b/crates/common/src/dotrain_order/calldata.rs index 74bf36ef6..88d4a3504 100644 --- a/crates/common/src/dotrain_order/calldata.rs +++ b/crates/common/src/dotrain_order/calldata.rs @@ -52,11 +52,16 @@ impl DotrainOrder { let mut calldatas = Vec::new(); - for output in &deployment.order.outputs { - if let Some(deposit_amount) = token_deposits.get(&output.token.key) { + for (i, output) in deployment.order.outputs.iter().enumerate() { + let output_token = output + .token + .as_ref() + .ok_or_else(|| DotrainOrderCalldataError::OutputTokenNotFound(i.to_string()))?; + + if let Some(deposit_amount) = token_deposits.get(&output_token.key) { let deposit_amount = deposit_amount.to_owned(); let deposit_args = DepositArgs { - token: output.token.address, + token: output_token.address, amount: deposit_amount, vault_id: U256::default(), }; @@ -75,7 +80,7 @@ impl DotrainOrder { .get_approve_calldata(transaction_args, allowance) .await?; calldatas.push(ApprovalCalldata { - token: output.token.address, + token: output_token.address, calldata: Bytes::copy_from_slice(&approve_call), }); } @@ -94,14 +99,18 @@ impl DotrainOrder { let mut calldatas = Vec::new(); for (i, output) in deployment.order.outputs.iter().enumerate() { + let output_token = output + .token + .as_ref() + .ok_or_else(|| DotrainOrderCalldataError::OutputTokenNotFound(i.to_string()))?; let vault_id = output .vault_id .ok_or(DotrainOrderCalldataError::VaultIdNotFound(i.to_string()))?; let token_deposit = token_deposits - .get(&(vault_id, output.token.address)) + .get(&(vault_id, output_token.address)) .ok_or(DotrainOrderCalldataError::TokenNotFound( - output.token.address.to_string(), + output_token.address.to_string(), ))?; if *token_deposit == U256::ZERO { @@ -109,7 +118,7 @@ impl DotrainOrder { } let calldata = DepositArgs { - token: output.token.address, + token: output_token.address, amount: token_deposit.to_owned(), vault_id, } @@ -150,12 +159,15 @@ pub enum DotrainOrderCalldataError { #[error("Orderbook not found")] OrderbookNotFound, - #[error("Token not found {0}")] - TokenNotFound(String), + #[error("Token not found for output index: {0}")] + OutputTokenNotFound(String), #[error("Vault id not found for output index: {0}")] VaultIdNotFound(String), + #[error("Token not found {0}")] + TokenNotFound(String), + #[error(transparent)] DepositError(#[from] DepositError), diff --git a/crates/settings/src/gui.rs b/crates/settings/src/gui.rs index a9a407388..0e01f758d 100644 --- a/crates/settings/src/gui.rs +++ b/crates/settings/src/gui.rs @@ -98,7 +98,7 @@ impl GuiConfigSource { .map(Arc::clone)?; Ok(GuiDeposit { - token: token.clone(), + token: Some(token.clone()), presets: deposit_source.presets.clone(), }) }) @@ -187,8 +187,8 @@ impl_all_wasm_traits!(GuiPreset); #[derive(Debug, PartialEq, Serialize, Deserialize, Clone)] #[cfg_attr(target_family = "wasm", derive(Tsify))] pub struct GuiDeposit { - #[typeshare(typescript(type = "Token"))] - pub token: Arc, + #[typeshare(typescript(type = "Token | undefined"))] + pub token: Option>, #[cfg_attr(target_family = "wasm", tsify(type = "string[]"))] pub presets: Vec, } @@ -334,7 +334,7 @@ impl YamlParseableValue for Gui { Some(format!( "token string missing for deposit index: {deposit_index} in gui deployment: {deployment_name}", )), - )?)?; + )?); let presets = require_vec( deposit_value, @@ -353,7 +353,7 @@ impl YamlParseableValue for Gui { .collect::, YamlError>>()?; let gui_deposit = GuiDeposit { - token: Arc::new(token), + token: token.ok().map(Arc::new), presets, }; Ok(gui_deposit) @@ -577,7 +577,10 @@ mod tests { assert_eq!(deployment.description, "test-deployment-description"); assert_eq!(deployment.deposits.len(), 1); let deposit = &deployment.deposits[0]; - assert_eq!(deposit.token.label, Some("test-token".to_string())); + assert_eq!( + deposit.token.as_ref().unwrap().label, + Some("test-token".to_string()) + ); assert_eq!(deposit.presets.len(), 2); assert_eq!(deposit.presets[0], "1.3".to_string()); assert_eq!(deposit.presets[1], "2.7".to_string()); @@ -839,22 +842,6 @@ gui: let yaml = r#" gui: - name: test - description: test - deployments: - deployment1: - name: test - description: test - deposits: - - token: test -"#; - let error = - Gui::parse_from_yaml_optional(vec![get_document(&format!("{yaml_prefix}{yaml}"))]) - .unwrap_err(); - assert_eq!(error, YamlError::KeyNotFound("test".to_string())); - - let yaml = r#" -gui: name: test description: test deployments: @@ -1115,12 +1102,12 @@ gui: let deployment = gui.deployments.get("deployment1").unwrap(); assert_eq!(deployment.name, "test"); assert_eq!(deployment.description, "test"); - assert_eq!(deployment.deposits[0].token.key, "token1"); + assert_eq!(deployment.deposits[0].token.as_ref().unwrap().key, "token1"); let deployment = gui.deployments.get("deployment2").unwrap(); assert_eq!(deployment.name, "test another"); assert_eq!(deployment.description, "test another"); - assert_eq!(deployment.deposits[0].token.key, "token2"); + assert_eq!(deployment.deposits[0].token.as_ref().unwrap().key, "token2"); } #[test] diff --git a/crates/settings/src/order.rs b/crates/settings/src/order.rs index 31565b52d..5123d76e7 100644 --- a/crates/settings/src/order.rs +++ b/crates/settings/src/order.rs @@ -22,8 +22,8 @@ use rain_orderbook_bindings::{impl_all_wasm_traits, wasm_traits::prelude::*}; #[cfg_attr(target_family = "wasm", derive(Tsify))] #[serde(rename_all = "kebab-case")] pub struct OrderIO { - #[typeshare(typescript(type = "Token"))] - pub token: Arc, + #[typeshare(typescript(type = "Token | undefined"))] + pub token: Option>, #[typeshare(typescript(type = "string"))] #[cfg_attr( target_family = "wasm", @@ -294,16 +294,18 @@ impl YamlParsableHash for Order { "token string missing in input index: {i} in order: {order_key}" )), )?; - let token = Token::parse_from_yaml(documents.clone(), &token_name)?; + let token = Token::parse_from_yaml(documents.clone(), &token_name); - if let Some(n) = &network { - if token.network != *n { - return Err(YamlError::ParseOrderConfigSourceError( - ParseOrderConfigSourceError::NetworkNotMatch, - )); + if let Ok(ref token) = token { + if let Some(n) = &network { + if token.network != *n { + return Err(YamlError::ParseOrderConfigSourceError( + ParseOrderConfigSourceError::NetworkNotMatch, + )); + } + } else { + network = Some(token.network.clone()); } - } else { - network = Some(token.network.clone()); } let vault_id = match optional_string(input, "vault-id") { @@ -312,7 +314,7 @@ impl YamlParsableHash for Order { }; Ok(OrderIO { - token: Arc::new(token), + token: token.ok().map(Arc::new), vault_id, }) }) @@ -333,16 +335,18 @@ impl YamlParsableHash for Order { "token string missing in output index: {i} in order: {order_key}" )), )?; - let token = Token::parse_from_yaml(documents.clone(), &token_name)?; + let token = Token::parse_from_yaml(documents.clone(), &token_name); - if let Some(n) = &network { - if token.network != *n { - return Err(YamlError::ParseOrderConfigSourceError( - ParseOrderConfigSourceError::NetworkNotMatch, - )); + if let Ok(ref token) = token { + if let Some(n) = &network { + if token.network != *n { + return Err(YamlError::ParseOrderConfigSourceError( + ParseOrderConfigSourceError::NetworkNotMatch, + )); + } + } else { + network = Some(token.network.clone()); } - } else { - network = Some(token.network.clone()); } let vault_id = match optional_string(output, "vault-id") { @@ -351,7 +355,7 @@ impl YamlParsableHash for Order { }; Ok(OrderIO { - token: Arc::new(token), + token: token.ok().map(Arc::new), vault_id, }) }) @@ -496,7 +500,7 @@ impl OrderConfigSource { if let Some(n) = &network { if v.network == *n { Ok(OrderIO { - token: v.clone(), + token: Some(v.clone()), vault_id: input.vault_id, }) } else { @@ -505,7 +509,7 @@ impl OrderConfigSource { } else { network = Some(v.network.clone()); Ok(OrderIO { - token: v.clone(), + token: Some(v.clone()), vault_id: input.vault_id, }) } @@ -526,7 +530,7 @@ impl OrderConfigSource { if let Some(n) = &network { if v.network == *n { Ok(OrderIO { - token: v.clone(), + token: Some(v.clone()), vault_id: output.vault_id, }) } else { @@ -535,7 +539,7 @@ impl OrderConfigSource { } else { network = Some(v.network.clone()); Ok(OrderIO { - token: v.clone(), + token: Some(v.clone()), vault_id: output.vault_id, }) } @@ -608,7 +612,7 @@ mod tests { order .inputs .iter() - .map(|v| v.token.clone()) + .map(|v| v.token.clone().unwrap()) .collect::>(), vec![token_input] ); @@ -616,7 +620,7 @@ mod tests { order .outputs .iter() - .map(|v| v.token.clone()) + .map(|v| v.token.clone().unwrap()) .collect::>(), vec![token_output] ); @@ -730,18 +734,6 @@ orders: ) ); - let yaml = r#" -orders: - order1: - inputs: - - token: eth -"#; - let error = Order::parse_all_from_yaml(vec![get_document(yaml)]).unwrap_err(); - assert_eq!( - error, - YamlError::ParseError("missing field: tokens".to_string()) - ); - let yaml = r#" networks: mainnet: @@ -794,6 +786,10 @@ networks: mainnet: rpc: "https://mainnet.infura.io" chain-id: "1" +deployers: + mainnet: + address: 0x0000000000000000000000000000000000000001 + network: mainnet tokens: token-one: network: mainnet @@ -803,6 +799,7 @@ tokens: address: 0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa orders: OrderOne: + deployer: mainnet inputs: - token: token-one outputs: @@ -811,6 +808,7 @@ orders: let yaml_two = r#" orders: OrderTwo: + deployer: mainnet inputs: - token: token-one outputs: @@ -835,6 +833,10 @@ networks: mainnet: rpc: "https://mainnet.infura.io" chain-id: "1" +deployers: + mainnet: + address: 0x0000000000000000000000000000000000000001 + network: mainnet tokens: token-one: network: mainnet @@ -844,6 +846,7 @@ tokens: address: 0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa orders: DuplicateOrder: + deployer: mainnet inputs: - token: token-one outputs: @@ -852,6 +855,7 @@ orders: let yaml_two = r#" orders: DuplicateOrder: + deployer: mainnet inputs: - token: token-one outputs: diff --git a/crates/settings/src/yaml/dotrain.rs b/crates/settings/src/yaml/dotrain.rs index 26c5e6956..78e74e5f3 100644 --- a/crates/settings/src/yaml/dotrain.rs +++ b/crates/settings/src/yaml/dotrain.rs @@ -222,12 +222,15 @@ mod tests { assert_eq!(order.inputs.len(), 1); let input = order.inputs.first().unwrap(); assert_eq!( - *input.token.clone().as_ref(), - ob_yaml.get_token("token1").unwrap() + *input.token.clone().as_ref().unwrap(), + ob_yaml.get_token("token1").unwrap().into() ); assert_eq!(input.vault_id, Some(U256::from(1))); let output = order.outputs.first().unwrap(); - assert_eq!(*output.token.as_ref(), ob_yaml.get_token("token2").unwrap()); + assert_eq!( + *output.token.as_ref().unwrap(), + ob_yaml.get_token("token2").unwrap().into() + ); assert_eq!(output.vault_id, Some(U256::from(2))); assert_eq!( *order.network.as_ref(), @@ -286,8 +289,8 @@ mod tests { assert_eq!(deployment.deposits.len(), 1); let deposit = &deployment.deposits[0]; assert_eq!( - *deposit.token.as_ref(), - ob_yaml.get_token("token1").unwrap() + *deposit.token.as_ref().unwrap(), + ob_yaml.get_token("token1").unwrap().into() ); assert_eq!(deposit.presets.len(), 2); assert_eq!(deposit.presets[0], "100".to_string()); From 150a6545717cce89eeefa8b78a13d813f32e4b1f Mon Sep 17 00:00:00 2001 From: Jamie Harding Date: Mon, 13 Jan 2025 18:28:41 +0100 Subject: [PATCH 071/142] binding --- .../src/lib/components/deployment/DeploymentSteps.svelte | 7 +++++-- .../src/lib/components/deployment/SelectToken.svelte | 2 ++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/packages/ui-components/src/lib/components/deployment/DeploymentSteps.svelte b/packages/ui-components/src/lib/components/deployment/DeploymentSteps.svelte index 469b508ff..18588586f 100644 --- a/packages/ui-components/src/lib/components/deployment/DeploymentSteps.svelte +++ b/packages/ui-components/src/lib/components/deployment/DeploymentSteps.svelte @@ -173,8 +173,11 @@ } $: if (selectTokens) { + console.log(selectTokens); getTokenInfos(); getDeposits(); + getAllTokenInputs(); + getAllTokenOutputs(); } $: if (gui) { @@ -309,7 +312,7 @@ {i} label="Input" vault={input} - {tokenInfos} + bind:tokenInfos vaultIds={inputVaultIds} {gui} /> @@ -323,7 +326,7 @@ {i} label="Output" vault={output} - {tokenInfos} + bind:tokenInfos vaultIds={outputVaultIds} {gui} /> diff --git a/packages/ui-components/src/lib/components/deployment/SelectToken.svelte b/packages/ui-components/src/lib/components/deployment/SelectToken.svelte index 4dd79ff58..56624b9f4 100644 --- a/packages/ui-components/src/lib/components/deployment/SelectToken.svelte +++ b/packages/ui-components/src/lib/components/deployment/SelectToken.svelte @@ -8,6 +8,7 @@ export let gui: DotrainOrderGui; export let selectTokens: Map; export let tokenInfos: TokenInfos; + let inputValue: string | null = null; let tokenInfo: TokenInfo | null = null; let error = ''; @@ -31,6 +32,7 @@ } catch { checking = false; error = 'Invalid address'; + selectTokens = gui.getSelectTokens(); } } } From 2df707f9f3d1da47ab0d9b2511d0be22188fbbb1 Mon Sep 17 00:00:00 2001 From: Jamie Harding Date: Mon, 13 Jan 2025 19:39:49 +0100 Subject: [PATCH 072/142] split deploy section headers --- .../deployment/DeploymentSectionHeader.svelte | 11 ++ .../deployment/DeploymentSteps.svelte | 100 ++++++++++++------ .../deployment/DepositButtons.svelte | 9 +- .../deployment/FieldDefinitionButtons.svelte | 12 +-- .../components/deployment/SelectToken.svelte | 42 ++++---- .../deployment/TokenInputOrOutput.svelte | 20 ++-- .../test-strategy-token-select.rain | 30 +++--- .../webapp/src/routes/deployment/+page.svelte | 2 +- 8 files changed, 131 insertions(+), 95 deletions(-) create mode 100644 packages/ui-components/src/lib/components/deployment/DeploymentSectionHeader.svelte diff --git a/packages/ui-components/src/lib/components/deployment/DeploymentSectionHeader.svelte b/packages/ui-components/src/lib/components/deployment/DeploymentSectionHeader.svelte new file mode 100644 index 000000000..5c716ac8d --- /dev/null +++ b/packages/ui-components/src/lib/components/deployment/DeploymentSectionHeader.svelte @@ -0,0 +1,11 @@ + + +
+

{title}

+

+ {description} +

+
diff --git a/packages/ui-components/src/lib/components/deployment/DeploymentSteps.svelte b/packages/ui-components/src/lib/components/deployment/DeploymentSteps.svelte index 18588586f..ed32627dd 100644 --- a/packages/ui-components/src/lib/components/deployment/DeploymentSteps.svelte +++ b/packages/ui-components/src/lib/components/deployment/DeploymentSteps.svelte @@ -4,6 +4,7 @@ import SelectToken from './SelectToken.svelte'; import TokenInputOrOutput from './TokenInputOrOutput.svelte'; import DropdownRadio from '../dropdown/DropdownRadio.svelte'; + import DeploymentSectionHeader from './DeploymentSectionHeader.svelte'; import { DotrainOrderGui, @@ -14,7 +15,8 @@ type GuiFieldDefinition, type SelectTokens, type TokenInfos, - type Vault + type Vault, + type GuiDetails } from '@rainlanguage/orderbook/js_api'; import { Button, Label, Spinner } from 'flowbite-svelte'; import { createWalletClient, custom, type Chain } from 'viem'; @@ -29,7 +31,8 @@ NO_FIELD_DEFINITIONS = 'Error loading field definitions', NO_DEPOSITS = 'Error loading deposits', NO_TOKEN_INPUTS = 'Error loading token inputs', - NO_TOKEN_OUTPUTS = 'Error loading token outputs' + NO_TOKEN_OUTPUTS = 'Error loading token outputs', + NO_GUI_DETAILS = 'Error getting GUI details' } const chains: Record = { @@ -107,6 +110,17 @@ handleDeploymentChange(selectedDeployment as string); } + let guiDetails: GuiDetails; + function getGuiDetails() { + if (!gui) return; + try { + guiDetails = gui.getGuiDetails(); + } catch (e) { + error = DeploymentStepErrors.NO_GUI_DETAILS; + console.error('Failed to get gui details:', e); + } + } + let tokenInfos: TokenInfos; function getTokenInfos() { if (!gui) return; @@ -173,11 +187,11 @@ } $: if (selectTokens) { - console.log(selectTokens); getTokenInfos(); getDeposits(); getAllTokenInputs(); getAllTokenOutputs(); + console.log(gui?.getCurrentDeployment()); } $: if (gui) { @@ -188,6 +202,7 @@ getDeposits(); getAllTokenInputs(); getAllTokenOutputs(); + getGuiDetails(); } export function getChainById(chainId: number): Chain { @@ -282,9 +297,23 @@ {/if} {#if gui} -
+
+ {#if guiDetails} +
+

+ {guiDetails.name} +

+

+ {guiDetails.description} +

+
+ {/if} + {#if selectTokens} - + {#each selectTokens.entries() as token} @@ -292,47 +321,50 @@ {/if} {#if allFieldDefinitions.length > 0} - {#each allFieldDefinitions as fieldDefinition} {/each} {/if} {#if allDeposits.length > 0} - {#each allDeposits as deposit} {/each} {/if} + {#if allTokenInputs.length > 0 && allTokenOutputs.length > 0} + + {#if allTokenInputs.length > 0} + {#each allTokenInputs as input, i} + + {/each} + {/if} - {#if allTokenInputs.length > 0} - - {#each allTokenInputs as input, i} - - {/each} - {/if} - - {#if allTokenOutputs.length > 0} - - {#each allTokenOutputs as output, i} - - {/each} + {#if allTokenOutputs.length > 0} + {#each allTokenOutputs as output, i} + + {/each} + {/if} {/if} - +
+ +
{/if} {/if} diff --git a/packages/ui-components/src/lib/components/deployment/DepositButtons.svelte b/packages/ui-components/src/lib/components/deployment/DepositButtons.svelte index 88f38a3da..db258afe5 100644 --- a/packages/ui-components/src/lib/components/deployment/DepositButtons.svelte +++ b/packages/ui-components/src/lib/components/deployment/DepositButtons.svelte @@ -7,6 +7,7 @@ } from '@rainlanguage/orderbook/js_api'; import { Input } from 'flowbite-svelte'; import ButtonSelectOption from './ButtonSelectOption.svelte'; + import DeploymentSectionHeader from './DeploymentSectionHeader.svelte'; export let deposit: GuiDeposit; export let gui: DotrainOrderGui; @@ -39,13 +40,7 @@
-
-

- {tokenName} -

-

Select deposit amount

-
- + {#if deposit.presets}
{#each deposit.presets as preset} diff --git a/packages/ui-components/src/lib/components/deployment/FieldDefinitionButtons.svelte b/packages/ui-components/src/lib/components/deployment/FieldDefinitionButtons.svelte index 5442c5115..3096b2d25 100644 --- a/packages/ui-components/src/lib/components/deployment/FieldDefinitionButtons.svelte +++ b/packages/ui-components/src/lib/components/deployment/FieldDefinitionButtons.svelte @@ -7,6 +7,7 @@ type GuiPreset } from '@rainlanguage/orderbook/js_api'; import ButtonSelectOption from './ButtonSelectOption.svelte'; + import DeploymentSectionHeader from './DeploymentSectionHeader.svelte'; export let fieldDefinition: GuiFieldDefinition; export let gui: DotrainOrderGui; @@ -33,18 +34,13 @@ gui = gui; currentFieldDefinition = gui?.getFieldValue(fieldDefinition.binding); } + + $: console.log(currentFieldDefinition);
- -
-

{fieldDefinition.name}

-

- {fieldDefinition.description} -

-
+ -
{#if fieldDefinition.presets} {#each fieldDefinition.presets as preset} diff --git a/packages/ui-components/src/lib/components/deployment/SelectToken.svelte b/packages/ui-components/src/lib/components/deployment/SelectToken.svelte index 56624b9f4..5540b3122 100644 --- a/packages/ui-components/src/lib/components/deployment/SelectToken.svelte +++ b/packages/ui-components/src/lib/components/deployment/SelectToken.svelte @@ -42,25 +42,27 @@ } -
-
- - -
- {#if checking} -
- - Checking... -
- {:else if tokenInfo} -
- - {tokenInfo.name} +
+
+
+ + {#if checking} +
+ + Checking... +
+ {:else if tokenInfo} +
+ + {tokenInfo.name} +
+ {:else if error} +
+ + {error} +
+ {/if}
- {:else if error} -
- - {error} -
- {/if} + +
diff --git a/packages/ui-components/src/lib/components/deployment/TokenInputOrOutput.svelte b/packages/ui-components/src/lib/components/deployment/TokenInputOrOutput.svelte index 6848027d6..47f6287b4 100644 --- a/packages/ui-components/src/lib/components/deployment/TokenInputOrOutput.svelte +++ b/packages/ui-components/src/lib/components/deployment/TokenInputOrOutput.svelte @@ -1,5 +1,5 @@ -
-
-

- {label} - {i + 1} ({tokenInfos.get(vault.token.address)?.symbol || 'Unknown'}) -

-
-
+
+
+
+ +
- Fixed limit order strategy + This strategy focuses on achieving a desired price level, regardless of market fluctuations, and does not adapt dynamically to changes in market conditions. deployments: - flare-token1-token2: - name: Buy token1 with token2 on flare. + flare-input-output: + name: Buy input with output on flare. description: - Buy token1 with token2 with a fixed ratio on flare network. + Buy input with output with a fixed ratio on flare network. deposits: - - token: token2 + - token: output min: 0 presets: - 0 @@ -65,12 +65,12 @@ gui: - 10000 fields: - binding: io-ratio - name: token1 to token2 ratio + name: Input to output ratio description: How many inputs do you want to have per one output? select-tokens: - - token1 - - token2 + - input + - output --- #io-ratio !The io ratio for the limit order. #calculate-io diff --git a/packages/webapp/src/routes/deployment/+page.svelte b/packages/webapp/src/routes/deployment/+page.svelte index 8edfae5bb..1843dec5f 100644 --- a/packages/webapp/src/routes/deployment/+page.svelte +++ b/packages/webapp/src/routes/deployment/+page.svelte @@ -2,6 +2,6 @@ import { DeploymentSteps } from '@rainlanguage/ui-components'; -
+
From afdec42386960b68592d1a77c9ea3aba2c6ff73f Mon Sep 17 00:00:00 2001 From: Jamie Harding Date: Mon, 13 Jan 2025 19:57:37 +0100 Subject: [PATCH 073/142] more design tweaks --- .../deployment/DeploymentSectionHeader.svelte | 4 +- .../deployment/DeploymentSteps.svelte | 96 ++++++++++--------- .../deployment/DepositButtons.svelte | 25 ++--- 3 files changed, 67 insertions(+), 58 deletions(-) diff --git a/packages/ui-components/src/lib/components/deployment/DeploymentSectionHeader.svelte b/packages/ui-components/src/lib/components/deployment/DeploymentSectionHeader.svelte index 5c716ac8d..45a8951b1 100644 --- a/packages/ui-components/src/lib/components/deployment/DeploymentSectionHeader.svelte +++ b/packages/ui-components/src/lib/components/deployment/DeploymentSectionHeader.svelte @@ -3,9 +3,9 @@ export let description: string = ''; -
+

{title}

-

+

{description}

diff --git a/packages/ui-components/src/lib/components/deployment/DeploymentSteps.svelte b/packages/ui-components/src/lib/components/deployment/DeploymentSteps.svelte index ed32627dd..0c944dca9 100644 --- a/packages/ui-components/src/lib/components/deployment/DeploymentSteps.svelte +++ b/packages/ui-components/src/lib/components/deployment/DeploymentSteps.svelte @@ -297,7 +297,7 @@ {/if} {#if gui} -
+
{#if guiDetails}

@@ -310,57 +310,65 @@ {/if} {#if selectTokens} - - - {#each selectTokens.entries() as token} - - {/each} +
+ + + {#each selectTokens.entries() as token} + + {/each} +
{/if} {#if allFieldDefinitions.length > 0} - {#each allFieldDefinitions as fieldDefinition} - - {/each} +
+ {#each allFieldDefinitions as fieldDefinition} + + {/each} +
{/if} {#if allDeposits.length > 0} - {#each allDeposits as deposit} - - {/each} +
+ {#each allDeposits as deposit} + + {/each} +
{/if} {#if allTokenInputs.length > 0 && allTokenOutputs.length > 0} - - {#if allTokenInputs.length > 0} - {#each allTokenInputs as input, i} - - {/each} - {/if} - - {#if allTokenOutputs.length > 0} - {#each allTokenOutputs as output, i} - - {/each} - {/if} +
+ + {#if allTokenInputs.length > 0} + {#each allTokenInputs as input, i} + + {/each} + {/if} + + {#if allTokenOutputs.length > 0} + {#each allTokenOutputs as output, i} + + {/each} + {/if} +
{/if}
diff --git a/packages/ui-components/src/lib/components/deployment/DepositButtons.svelte b/packages/ui-components/src/lib/components/deployment/DepositButtons.svelte index db258afe5..273299c9e 100644 --- a/packages/ui-components/src/lib/components/deployment/DepositButtons.svelte +++ b/packages/ui-components/src/lib/components/deployment/DepositButtons.svelte @@ -39,10 +39,13 @@ } -
- +
+ {#if deposit.presets} -
+
{#each deposit.presets as preset} {/if} -
- handleInput(e)} - /> -
+ handleInput(e)} + />
From 02d7dc4027a765a7c2bb6a70cd2741ee84f94538 Mon Sep 17 00:00:00 2001 From: Jamie Harding Date: Mon, 13 Jan 2025 20:13:40 +0100 Subject: [PATCH 074/142] styling more --- .../components/deployment/DeploymentSteps.svelte | 15 ++++++++------- .../components/deployment/DepositButtons.svelte | 2 +- .../deployment/FieldDefinitionButtons.svelte | 14 ++++++-------- .../lib/components/deployment/SelectToken.svelte | 2 +- .../deployment/TokenInputOrOutput.svelte | 2 +- .../webapp/src/routes/deployment/+page.svelte | 2 +- 6 files changed, 18 insertions(+), 19 deletions(-) diff --git a/packages/ui-components/src/lib/components/deployment/DeploymentSteps.svelte b/packages/ui-components/src/lib/components/deployment/DeploymentSteps.svelte index 0c944dca9..e5e397884 100644 --- a/packages/ui-components/src/lib/components/deployment/DeploymentSteps.svelte +++ b/packages/ui-components/src/lib/components/deployment/DeploymentSteps.svelte @@ -297,7 +297,7 @@ {/if} {#if gui} -
+
{#if guiDetails}

@@ -315,10 +315,11 @@ title="Select Tokens" description="Select the tokens that you want to use in your order." /> - - {#each selectTokens.entries() as token} - - {/each} +
+ {#each selectTokens.entries() as token} + + {/each} +

{/if} @@ -331,7 +332,7 @@ {/if} {#if allDeposits.length > 0} -
+
{#each allDeposits as deposit} {/each} @@ -371,7 +372,7 @@
{/if}
- +
{/if} diff --git a/packages/ui-components/src/lib/components/deployment/DepositButtons.svelte b/packages/ui-components/src/lib/components/deployment/DepositButtons.svelte index 273299c9e..92b566ff5 100644 --- a/packages/ui-components/src/lib/components/deployment/DepositButtons.svelte +++ b/packages/ui-components/src/lib/components/deployment/DepositButtons.svelte @@ -39,7 +39,7 @@ } -
+
-
+
-
- {#if fieldDefinition.presets} + {#if fieldDefinition.presets} +
{#each fieldDefinition.presets as preset} {/each} - {/if} -
+
+ {/if} {#if fieldDefinition.binding !== 'is-fast-exit'} -
+
-
+
diff --git a/packages/ui-components/src/lib/components/deployment/TokenInputOrOutput.svelte b/packages/ui-components/src/lib/components/deployment/TokenInputOrOutput.svelte index 47f6287b4..433857af5 100644 --- a/packages/ui-components/src/lib/components/deployment/TokenInputOrOutput.svelte +++ b/packages/ui-components/src/lib/components/deployment/TokenInputOrOutput.svelte @@ -11,7 +11,7 @@ export let gui: DotrainOrderGui; -
+