Skip to content

Commit 953eeca

Browse files
committed
Fully updated to v0.4.0
1 parent 1aba892 commit 953eeca

21 files changed

+447
-161
lines changed

1-exchanges/RaDEX/README.md

+16-12
Original file line numberDiff line numberDiff line change
@@ -186,30 +186,34 @@ The first thing that we need to do now is to create four different accounts to u
186186

187187
```sh
188188
OP1=$(resim new-account)
189+
export PRIV_KEY1=$(echo "$OP1" | sed -nr "s/Private key: ([[:alnum:]_]+)/\1/p")
189190
export PUB_KEY1=$(echo "$OP1" | sed -nr "s/Public key: ([[:alnum:]_]+)/\1/p")
190-
export ACC_ADDRESS1=$(echo "$OP1" | sed -nr "s/Account address: ([[:alnum:]_]+)/\1/p")
191+
export ACC_ADDRESS1=$(echo "$OP1" | sed -nr "s/Account component address: ([[:alnum:]_]+)/\1/p")
191192
OP2=$(resim new-account)
193+
export PRIV_KEY2=$(echo "$OP2" | sed -nr "s/Private key: ([[:alnum:]_]+)/\1/p")
192194
export PUB_KEY2=$(echo "$OP2" | sed -nr "s/Public key: ([[:alnum:]_]+)/\1/p")
193-
export ACC_ADDRESS2=$(echo "$OP2" | sed -nr "s/Account address: ([[:alnum:]_]+)/\1/p")
195+
export ACC_ADDRESS2=$(echo "$OP2" | sed -nr "s/Account component address: ([[:alnum:]_]+)/\1/p")
194196
OP3=$(resim new-account)
197+
export PRIV_KEY3=$(echo "$OP3" | sed -nr "s/Private key: ([[:alnum:]_]+)/\1/p")
195198
export PUB_KEY3=$(echo "$OP3" | sed -nr "s/Public key: ([[:alnum:]_]+)/\1/p")
196-
export ACC_ADDRESS3=$(echo "$OP3" | sed -nr "s/Account address: ([[:alnum:]_]+)/\1/p")
199+
export ACC_ADDRESS3=$(echo "$OP3" | sed -nr "s/Account component address: ([[:alnum:]_]+)/\1/p")
197200
OP4=$(resim new-account)
201+
export PRIV_KEY4=$(echo "$OP4" | sed -nr "s/Private key: ([[:alnum:]_]+)/\1/p")
198202
export PUB_KEY4=$(echo "$OP4" | sed -nr "s/Public key: ([[:alnum:]_]+)/\1/p")
199-
export ACC_ADDRESS4=$(echo "$OP4" | sed -nr "s/Account address: ([[:alnum:]_]+)/\1/p")
203+
export ACC_ADDRESS4=$(echo "$OP4" | sed -nr "s/Account component address: ([[:alnum:]_]+)/\1/p")
200204
```
201205

202206
With the four accounts created, let's give some context as to what we will be doing next. The first thing that we wish to do is to create a number of test tokens that we can use to test out the functionality of the DEX. We would like Account 1 to be the creator of these test tokens and for it to then send some of these tokens to the other accounts so that they can test the DEX. Since Account 1 is the account that will be used for hte creation of the tokens, we need to set it as the default account:
203207

204208
```sh
205-
$ resim set-default-account $ACC_ADDRESS1 $PUB_KEY1
209+
$ resim set-default-account $ACC_ADDRESS1 $PUB_KEY1 $PRIV_KEY1
206210
Default account updated!
207211
```
208212

209-
The file [`token_creation_and_funding.rtm`](./transactions/token_creation_and_funding.rtm) contains the instructions needed for account 1 to create 8 different tokens (we will have a total of 9 tokens after this transaction as we do not need to create XRD) and then fund the 3 other accounts created before depositing all of the remaining tokens back into account 1. All of this will be done in one single neat atomically composed transaction that creates the tokens and deposits them into the accounts. To run the transaction file, run the following command:
213+
The files [`token_creation.rtm`](./transactions/token_creation.rtm), and [`token_funding.rtm`](./transactions/token_funding.rtm) contain the instructions needed for account 1 to create 8 different tokens (we will have a total of 9 tokens after this transaction as we do not need to create XRD) and then fund the 3 other accounts created before depositing all of the remaining tokens back into account 1. To run the transaction file, run the following command:
210214

211215
```sh
212-
resim run transactions/token_creation_and_funding.rtm
216+
resim run transactions/token_creation.rtm && resim run transactions/token_funding.rtm
213217
```
214218

215219
When this transaction runs, all of the accounts that we had created would now have 100,000 of some of the tokens that we will be using for the testing of the DEX. We can now publish the RaDEX package and also instantiate a new RaDEX component by running the following commands:
@@ -250,7 +254,7 @@ The [`creating_initial_liquidity_pools.rtm`](./transactions/creating_initial_liq
250254
Now that the process that we will be following is somewhat clear, let's get into running this transaction using Lynn's account. First things first, let's make sure that Lynn's account (Account 1) is set the default account in resim:
251255

252256
```sh
253-
$ resim set-default-account $ACC_ADDRESS1 $PUB_KEY1
257+
$ resim set-default-account $ACC_ADDRESS1 $PUB_KEY1 $PRIV_KEY1
254258
Default account updated!
255259
```
256260

@@ -293,7 +297,7 @@ Josh has decided to use RaDEX to perform the swap of BTC for USDT as RaDEX has t
293297
Let's now run the needed transaction manifest file for Josh to perform his swap of BTC for USDT. We first need to switch the default account in resim to Josh's account by doing the following:
294298
295299
```sh
296-
$ resim set-default-account $ACC_ADDRESS2 $PUB_KEY2
300+
$ resim set-default-account $ACC_ADDRESS2 $PUB_KEY2 $PRIV_KEY2
297301
Default account updated!
298302
```
299303
@@ -368,7 +372,7 @@ As can be seen in the diagram above, the first step in the transaction is the wi
368372
Let's now to get to work and try out this transaction. Let's begin by switching to Tim's account:
369373
370374
```sh
371-
$ resim set-default-account $ACC_ADDRESS3 $PUB_KEY3
375+
$ resim set-default-account $ACC_ADDRESS3 $PUB_KEY3 $PRIV_KEY3
372376
Default account updated!
373377
```
374378
@@ -405,7 +409,7 @@ Alfred has decided that he wants to sell some of the Bitcoin that he owns for US
405409
Now that we understand what will be done, we can go ahead and perform this transaction. Let's begin by switching over to Alfred's account:
406410
407411
```sh
408-
$ resim set-default-account $ACC_ADDRESS4 $PUB_KEY4
412+
$ resim set-default-account $ACC_ADDRESS4 $PUB_KEY4 $PRIV_KEY4
409413
Default account updated!
410414
```
411415
@@ -435,7 +439,7 @@ With the last example we are going back to Lynn (Account 1). After providing liq
435439
Let's begin by switching the default account in resim to be Lynn's account:
436440
437441
```sh
438-
$ resim set-default-account $ACC_ADDRESS1 $PUB_KEY1
442+
$ resim set-default-account $ACC_ADDRESS1 $PUB_KEY1 $PRIV_KEY1
439443
Default account updated!
440444
```
441445
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# Creating a new RaDEX component from the package address by calling the `new` function on the blueprint. This `new`
2+
# function is a function which does not take any arguments nor does it return anything. Meaning that to create a new
3+
# RaDEX all that we need to do is to call the function.
4+
CALL_FUNCTION PackageAddress("<<<package_address>>>") "RaDEX" "new";
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
# In order for the trading on the DEX to begin, we first need to have liquidity in the DEX so that users can swap their
2+
# tokens for another tokens. In this RTM file, we are adding liquidity to the DEX from the account that created the
3+
# test tokens.
4+
5+
# Withdrawing the total amount of tokens from the account and into the transaction worktop.
6+
CALL_METHOD ComponentAddress("<<<account1_address>>>") "withdraw" ResourceAddress("030000000000000000000000000000000000000000000000000004"); #Withdrawing XRD
7+
CALL_METHOD ComponentAddress("<<<account1_address>>>") "withdraw" ResourceAddress("<<<tether_resource_address>>>"); #Withdrawing USDT
8+
CALL_METHOD ComponentAddress("<<<account1_address>>>") "withdraw" ResourceAddress("<<<quant_resource_address>>>"); #Withdrawing QNT
9+
CALL_METHOD ComponentAddress("<<<account1_address>>>") "withdraw" ResourceAddress("<<<cardano_resource_address>>>"); #Withdrawing ADA
10+
CALL_METHOD ComponentAddress("<<<account1_address>>>") "withdraw" ResourceAddress("<<<bitcoin_resource_address>>>"); #Withdrawing BTC
11+
CALL_METHOD ComponentAddress("<<<account1_address>>>") "withdraw" ResourceAddress("<<<litecoin_resource_address>>>"); #Withdrawing LTC
12+
CALL_METHOD ComponentAddress("<<<account1_address>>>") "withdraw" ResourceAddress("<<<bnb_resource_address>>>"); #Withdrawing BNB
13+
CALL_METHOD ComponentAddress("<<<account1_address>>>") "withdraw" ResourceAddress("<<<doge_resource_address>>>"); #Withdrawing DOGE
14+
15+
# Creating an XRD-USDT pool with: 14,000 USDT and 100,000 XRD.
16+
TAKE_FROM_WORKTOP_BY_AMOUNT Decimal("100000.00") ResourceAddress("030000000000000000000000000000000000000000000000000004") Bucket("XRD_USDT_bucket");
17+
TAKE_FROM_WORKTOP_BY_AMOUNT Decimal("14000.00") ResourceAddress("<<<tether_resource_address>>>") Bucket("USDT_XRD_bucket");
18+
CALL_METHOD ComponentAddress("<<<component_address>>>") "add_liquidity" Bucket("USDT_XRD_bucket") Bucket("XRD_USDT_bucket");
19+
20+
# Creating a QNT-USDT pool with: 100,000 USDT and 865.276 QNT.
21+
TAKE_FROM_WORKTOP_BY_AMOUNT Decimal("865.276") ResourceAddress("<<<quant_resource_address>>>") Bucket("QNT_USDT_bucket");
22+
TAKE_FROM_WORKTOP_BY_AMOUNT Decimal("100000.00") ResourceAddress("<<<tether_resource_address>>>") Bucket("USDT_QNT_bucket");
23+
CALL_METHOD ComponentAddress("<<<component_address>>>") "add_liquidity" Bucket("USDT_QNT_bucket") Bucket("QNT_USDT_bucket");
24+
25+
# Creating a ADA-USDT pool with: 100,000 USDT and 105263.1578 ADA
26+
TAKE_FROM_WORKTOP_BY_AMOUNT Decimal("105263.1578") ResourceAddress("<<<cardano_resource_address>>>") Bucket("ADA_USDT_bucket");
27+
TAKE_FROM_WORKTOP_BY_AMOUNT Decimal("100000.00") ResourceAddress("<<<tether_resource_address>>>") Bucket("USDT_ADA_bucket");
28+
CALL_METHOD ComponentAddress("<<<component_address>>>") "add_liquidity" Bucket("USDT_ADA_bucket") Bucket("ADA_USDT_bucket");
29+
30+
# Creating a BTC-USDT pool with: 10,000,000 USDT tokens and 232.558 BTC
31+
TAKE_FROM_WORKTOP_BY_AMOUNT Decimal("232.558") ResourceAddress("<<<bitcoin_resource_address>>>") Bucket("BTC_USDT_bucket");
32+
TAKE_FROM_WORKTOP_BY_AMOUNT Decimal("10000000.00") ResourceAddress("<<<tether_resource_address>>>") Bucket("USDT_BTC_bucket");
33+
CALL_METHOD ComponentAddress("<<<component_address>>>") "add_liquidity" Bucket("USDT_BTC_bucket") Bucket("BTC_USDT_bucket");
34+
35+
# Creating an LTC-BTC pool with: 23.1835 BTC and 8720.6767 LTC
36+
TAKE_FROM_WORKTOP_BY_AMOUNT Decimal("8720.6767") ResourceAddress("<<<litecoin_resource_address>>>") Bucket("LTC_BTC_bucket");
37+
TAKE_FROM_WORKTOP_BY_AMOUNT Decimal("23.1835") ResourceAddress("<<<bitcoin_resource_address>>>") Bucket("BTC_LTC_bucket");
38+
CALL_METHOD ComponentAddress("<<<component_address>>>") "add_liquidity" Bucket("LTC_BTC_bucket") Bucket("BTC_LTC_bucket");
39+
40+
# Creating an ADA-XRD pool with: 19526.357 ADA and 67485 XRD.
41+
TAKE_FROM_WORKTOP_BY_AMOUNT Decimal("67485") ResourceAddress("030000000000000000000000000000000000000000000000000004") Bucket("XRD_ADA_bucket");
42+
TAKE_FROM_WORKTOP_BY_AMOUNT Decimal("19526.357") ResourceAddress("<<<cardano_resource_address>>>") Bucket("ADA_XRD_bucket");
43+
CALL_METHOD ComponentAddress("<<<component_address>>>") "add_liquidity" Bucket("XRD_ADA_bucket") Bucket("ADA_XRD_bucket");
44+
45+
# Creating an LTC-XRD pool with: 88.67 LTC and 67485 XRD
46+
TAKE_FROM_WORKTOP_BY_AMOUNT Decimal("67485") ResourceAddress("030000000000000000000000000000000000000000000000000004") Bucket("XRD_LTC_bucket");
47+
TAKE_FROM_WORKTOP_BY_AMOUNT Decimal("88.67") ResourceAddress("<<<litecoin_resource_address>>>") Bucket("LTC_XRD_bucket");
48+
CALL_METHOD ComponentAddress("<<<component_address>>>") "add_liquidity" Bucket("XRD_LTC_bucket") Bucket("LTC_XRD_bucket");
49+
50+
# Creating an LTC-BNB pool with: 88.67 LTC and 24.2187 BNB
51+
TAKE_FROM_WORKTOP_BY_AMOUNT Decimal("24.2187") ResourceAddress("<<<bnb_resource_address>>>") Bucket("BNB_LTC_bucket");
52+
TAKE_FROM_WORKTOP_BY_AMOUNT Decimal("88.67") ResourceAddress("<<<litecoin_resource_address>>>") Bucket("LTC_BNB_bucket");
53+
CALL_METHOD ComponentAddress("<<<component_address>>>") "add_liquidity" Bucket("BNB_LTC_bucket") Bucket("LTC_BNB_bucket");
54+
55+
# Creating an BNB-DOGE pool with: 2481.57 BNB and 7692307.692 DOGE
56+
TAKE_FROM_WORKTOP_BY_AMOUNT Decimal("2481.57") ResourceAddress("<<<bnb_resource_address>>>") Bucket("BNB_DOGE_bucket");
57+
TAKE_FROM_WORKTOP_BY_AMOUNT Decimal("7692307.692") ResourceAddress("<<<doge_resource_address>>>") Bucket("DOGE_BNB_bucket");
58+
CALL_METHOD ComponentAddress("<<<component_address>>>") "add_liquidity" Bucket("BNB_DOGE_bucket") Bucket("DOGE_BNB_bucket");
59+
60+
# Deposit the tracking tokens back into the account
61+
CALL_METHOD_WITH_ALL_RESOURCES ComponentAddress("<<<account1_address>>>") "deposit_batch";
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# The owner of account 1 had created a number of liquidity pools and now wishes to withdraw the liquidity that they
2+
# had provided to RaDEX so that they can get their portion of the swap fees into their wallet.
3+
4+
# Withdrawing all of the tracking tokens of the BTC/USDT pool from account 1 and creating a bucket of them
5+
CALL_METHOD ComponentAddress("<<<account1_address>>>") "withdraw_by_amount" Decimal("100") ResourceAddress("<<<btc_usdt_resource_address>>>");
6+
TAKE_FROM_WORKTOP ResourceAddress("<<<btc_usdt_resource_address>>>") Bucket("tracking_tokens_bucket");
7+
8+
# Calling the `remove_liquidity` on the RaDEX component with the tracking tokens
9+
CALL_METHOD ComponentAddress("<<<component_address>>>") "remove_liquidity" Bucket("tracking_tokens_bucket");
10+
11+
# Depositing all of the tokens on the worktop into the account
12+
CALL_METHOD_WITH_ALL_RESOURCES ComponentAddress("<<<account1_address>>>") "deposit_batch";
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
# The owner of account 3 wants to exchange some of the ADA that they own for some DOGE and wants to use RaDEX for this
2+
# swap. However, they can't find a direct pair for the swapping of ADA to DOGE.
3+
#
4+
# Luckily, even though there does not exist a liquidity pool for ADA/DOGE, there does exist a path that can be taken to
5+
# swap ADA for DOGE tokens by going through a number of liquidity pools that connect these two tokens. The path of
6+
# liquidity pools that will be taken to swap ADA for DOGE is as follows:
7+
#
8+
# ADA -> ADA/XRD -> XRD/LTC -> LTC/BNB -> BNB/DOGE -> DOGE
9+
#
10+
# The swap can be even done in a single transaction using the RTM files to perform everything neatly and cleanly in a
11+
# single transaction. In fact, performing the swap in a single transaction gives security to the owner of account 3 that
12+
# this swapping between different liquidity pools won't hinder on the amount of DOGE that they get at the end. If it
13+
# affected it in a deeply negative way, then the assertion check at the end of the transaction file fails and everything
14+
# goes back to normal almost as if nothing had happened.
15+
16+
# The owner of account 3 wishes to exchange 100 ADA for whatever amount of DOGE they can get. So, we withdraw 100 ADA
17+
# into the transaction worktop and then into a bucket.
18+
CALL_METHOD ComponentAddress("<<<account3_address>>>") "withdraw_by_amount" Decimal("100.00") ResourceAddress("<<<cardano_resource_address>>>");
19+
TAKE_FROM_WORKTOP ResourceAddress("<<<cardano_resource_address>>>") Bucket("ADA_bucket");
20+
21+
# Swapping ADA for XRD and then putting the XRD in a bucket
22+
CALL_METHOD ComponentAddress("<<<component_address>>>") "swap" Bucket("ADA_bucket") ResourceAddress("030000000000000000000000000000000000000000000000000004");
23+
TAKE_FROM_WORKTOP ResourceAddress("030000000000000000000000000000000000000000000000000004") Bucket("XRD_bucket");
24+
25+
# Swapping XRD for LTC and then putting the LTC in a bucket
26+
CALL_METHOD ComponentAddress("<<<component_address>>>") "swap" Bucket("XRD_bucket") ResourceAddress("<<<litecoin_resource_address>>>");
27+
TAKE_FROM_WORKTOP ResourceAddress("<<<litecoin_resource_address>>>") Bucket("LTC_bucket");
28+
29+
# Swapping LTC for BNB and then putting the BNB in a bucket
30+
CALL_METHOD ComponentAddress("<<<component_address>>>") "swap" Bucket("LTC_bucket") ResourceAddress("<<<bnb_resource_address>>>");
31+
TAKE_FROM_WORKTOP ResourceAddress("<<<bnb_resource_address>>>") Bucket("BNB_bucket");
32+
33+
# Swapping BNB for DOGE and asserting that we obtained at least 300 DOGE from this long swap. If the assertion goes
34+
# through then we deposit everything in the transaction worktop into the account.
35+
CALL_METHOD ComponentAddress("<<<component_address>>>") "swap" Bucket("BNB_bucket") ResourceAddress("<<<doge_resource_address>>>");
36+
ASSERT_WORKTOP_CONTAINS_BY_AMOUNT Decimal("300") ResourceAddress("<<<doge_resource_address>>>");
37+
38+
CALL_METHOD_WITH_ALL_RESOURCES ComponentAddress("<<<account3_address>>>") "deposit_batch";
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# Unfortunately, the owner of account 2 is in some kind of financial trouble and needs some USDT urgently. They have
2+
# found that they need about $500,000 for the financial trouble that they are in. The owner of account 2 has decided to
3+
# sell some of the bitcoin that they own to help them with the financial issues that they have. They're not interested
4+
# in selling more than what they need and they're only willing to sell any amount of bitcoin below or equal to 20 BTC
5+
# to help them with their financial issues.
6+
#
7+
# The owner of account 2 have decided to use RaDEX to sell some of their BTC for exactly $500,000. This RTM file contains
8+
# the instructions that would be carried out in order to sell enough BTC to cover the financial needs of the owner of
9+
# account 2.
10+
11+
# Withdrawing 20 BTC into the transaction worktop to exchange them for USDT
12+
CALL_METHOD ComponentAddress("<<<account2_address>>>") "withdraw_by_amount" Decimal("20") ResourceAddress("<<<bitcoin_resource_address>>>");
13+
14+
# Create a bucket from the 20 withdrawn BTC
15+
TAKE_FROM_WORKTOP_BY_AMOUNT Decimal("20") ResourceAddress("<<<bitcoin_resource_address>>>") Bucket("btc_bucket");
16+
17+
# Calling the `swap_tokens_for_exact_tokens` method on the RaDEX component to attempt to swap the 20 BTC for the
18+
# $500,000 that they need.
19+
CALL_METHOD ComponentAddress("<<<component_address>>>") "swap_tokens_for_exact_tokens" Bucket("btc_bucket") ResourceAddress("<<<tether_resource_address>>>") Decimal("500000");
20+
21+
# Checking to ensure that after this method call, that $500,000 are present in the workop. If the 500,000 USDT tokens are
22+
# not present in the transaction worktop, then the transaction fails and the owner of account 2 gets back their BTC
23+
# tokens. This is an extra check that's all.
24+
ASSERT_WORKTOP_CONTAINS_BY_AMOUNT Decimal("500000") ResourceAddress("<<<tether_resource_address>>>");
25+
26+
# If the above method call was successful, we deposit everything from the transaction worktop and back into the account
27+
CALL_METHOD_WITH_ALL_RESOURCES ComponentAddress("<<<account2_address>>>") "deposit_batch";
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# The owner of account 4 (let's call him Alfred for the purposes of this example) has just heard of yield framing and how
2+
# that he could make some extra income by providing liquidity to a liquidity pool and earning a percentage of the pool
3+
# fees that are imposed on swaps.
4+
#
5+
# Alfred has decided that he wants to sell some of the Bitcoin that he owns for USDT and then he wants to provide liquidity
6+
# to the XRD/USDT liquidity pool in RaDEX. This transaction manifest file contains the transaction instructions for the
7+
# selling of Bitcoin tokens for USDT and then providing liquidity to the XRD/USDT liquidity pool.
8+
9+
# Withdrawing 500,000 XRD and 40 BTC from Alfred's account and into the transaction worktop
10+
CALL_METHOD ComponentAddress("<<<account4_address>>>") "withdraw_by_amount" Decimal("500000") ResourceAddress("030000000000000000000000000000000000000000000000000004");
11+
CALL_METHOD ComponentAddress("<<<account4_address>>>") "withdraw_by_amount" Decimal("40") ResourceAddress("<<<bitcoin_resource_address>>>");
12+
13+
# Creating a bucket of the withdrawn Bitcoin and then swapping it for USDT
14+
TAKE_FROM_WORKTOP ResourceAddress("<<<bitcoin_resource_address>>>") Bucket("BTC_bucket");
15+
CALL_METHOD ComponentAddress("<<<component_address>>>") "swap" Bucket("BTC_bucket") ResourceAddress("<<<tether_resource_address>>>");
16+
17+
# At this point, the transaction worktop should include USDT tokens if the swap has indeed gone through correctly, so
18+
# we take the USDT tokens and put them in a bucket and we also put the XRD from the worktop into a bucket.
19+
TAKE_FROM_WORKTOP ResourceAddress("<<<tether_resource_address>>>") Bucket("USDT_bucket");
20+
TAKE_FROM_WORKTOP ResourceAddress("030000000000000000000000000000000000000000000000000004") Bucket("XRD_bucket");
21+
22+
# Adding liquidity to the XRD/USDT liquidity pool with all of the XRD and USDT available in the transaction worktop
23+
CALL_METHOD ComponentAddress("<<<component_address>>>") "add_liquidity" Bucket("XRD_bucket") Bucket("USDT_bucket");
24+
25+
# Depositing the tracking tokens we get back into Alfred's account.
26+
CALL_METHOD_WITH_ALL_RESOURCES ComponentAddress("<<<account4_address>>>") "deposit_batch";

0 commit comments

Comments
 (0)