Step 4
Figure out how to get the flag
Take a look at the smart contract source code
The first step in figuring out how to get the flag is view the source code. The source code was provided was the event and can be viewed here. Navigate to Module.move in the source directory to find the module source code.
The flag
Take a moment to look through the module. Try to locate the get_flag() function.
This time the get_flag() function requires a Flashlender to be included in the function call. The Flag event will be emitted if the to_lend attribute of the Flashlender is 0.
// check whether you can get the flag
public entry fun get_flag(self: &mut FlashLender, ctx: &mut TxContext) {
if (balance::value(&self.to_lend) == 0) {
event::emit(Flag { user: tx_context::sender(ctx), flag: true });
}
}The Flashlender
The Flashlender is an struct in the module.
struct FlashLender has key {
id: UID,
to_lend: Balance<FLASH>,
last: u64,
lender: VecMap<address, u64>
}The Flashlender struct has four attributes, id, to_lend, last, and lender. We are seeing some interesting types being assigned these attributes. id is a new id generate from the object package. This just returns an unique id that can be used to label the Flashlender with. to_lend has a type balance<FLASH> which represents the specific account's balance of the FLASH coin in this case. lender has a type VecMap<address, u64> which is a mapping (aka a dictionary or hash table) that maps account addresses to numbers (u64).
The bigger picture
The module contains a function that is called init. In move, the init function is called during the deployment of the module (see docs). We can look at this function to get a better understanding of what has been done so far.
The module's init function creates a new coin collection, mints 1000 of the new coins, calls the create_lend() function, and transfer blank coins to the owner account. You may have noticed the use of coin:: throughout the module. This is how a module references code from another deployed (AKA published) module. The coin module being used was created by the Sui team. The source code for the coin module can be viewed here. Lets take a look at the create_lend() function.
The create_lend() function looks to be responsible for creating and initializing a new Flashlender object. Again, try taking a look the modules that is being used by this module. Now that we know what has been done since deployment of the module, we can continue trying to get the flag.
We can also confirm this by viewing the deployed Flashlender object from the deployment transaction page on the Sui explorer. We can find the object by determining which of the addresses in the created section corresponds to the Flashlender. We can confirm that to_lend amount as well as view the mapping for the lender list (in the code block below).

Take a moment to figure out what needs to be done in order to get the balance in a Flashlender object's to_lend to 0. Look at all of the functions we can call (entry functions).
The only functions that are marked as entry are get_flag(), deposit(), and withdraw().
The withdraw and deposit are similar as they both read and write to deployed Flashlender objects. The deposit function allows a user to add some of their own FLASH coins to the Flashlender, while the withdraw function lets user remove their coins from the Flashlender (only if they had previously deposited coins in).
Unfortunately, we cannot withdraw the 1000 coins that are currently in the Flashlender since we were not the ones that deposited that amount. Thus, we need more than the entry functions to help us.
Take a look at the other functions to look for a way to decrease the amount in the Flashlender.
The functions balance() and check() do only view and verify data so they would not be helpful in editing the Flashlender. The loan() and the repay() functions, however, could potentially help us.
The loan() function allows a user to borrow an amount of coins that are in the Flashlender, while the repay() functions allows a user to repay a loan. We should be able to use the loan() function to decrease the balance of the Flashlender and then call the get_flag() function.
The only issue is that the loan() function is not marked as entry which means the function can only be called by other modules. We will need to create and deploy (aka publish) our own module that we will use to call these functions.
Creating the move module
We need to create a module that will take the deployed Flashlender object, take borrow the 1000 coins, get the flag, and than repay the loan.
Pull down flash loan module source code. Make sure to include the whole repository include the toml file.
In order to interact with our specific instance of the flash loan module, we need to make a change to the source code's Move.toml file. In the [addresses] section, replace the movectf address with our deployed module's address (can be found from the deployment transaction).
We then need to set up the environment for our new module. In the same directory that the source code directory is in, create the module environment with, sui move new flash_loan_solution. This should create a directory similar to the flash loan source code directory.
We need to edit the generated Move.toml file for our solution module. In the [dependencies] section, add this, movectf = { local = "<PATH_TO_SOURCE_CODE>) } with the path to the flash loan source code directory.
Create a file in the solution source directory called, solution.move. Paste the below move code into the file.
Take a moment to understand what the solution module is doing and how it is interacting with the already deployed flash loan module.
The first thing we did in the module is define what we are using from other modules, TxContext from the Sui core modules and the deployed flash loan module. Then we can create the function that we will call to interact with the flash loan module with. We are able to get the flag after we borrow the 1000 coins. Note that we will need to pay back the loan before we exit the function. This is due to the nature of the two return values of the loan function, borrowed_coins and receipt. The structs for these two variables are not droppable which means they can not be left unused by the end of the function call. Head here for more information on the drop struct attribute.
Run sui move build in the solution root directory to compile the module. You should get the output shown below.
Once the module is successfully built, we can publish it. Run sui client publish --path <path-to-solution-directory> --gas-budget 30000. Note, you will need to setup an account with the sui client if you have not yet. Follow the prompts in the CLI to do so. Once the module is published, you should see a similar output that contains information like the deployment transaction hash. Take note of the solution module's address.
Now we can build a script to call our deployed module.
Build script to interact with the deployed solution module
We need to create a script to call the function in our solution module in order to call the functions in the flash loan module.
Use the script to call the get_flag() function
Results from calling the script:
View the transaction on the Sui blockchain explorer
The results from the script shows the dev address as well as the transaction information, including the transaction hash which we could use to look up the transaction in the Sui block explorer. Look at the events emitted during the transaction to double check that the Flag event was emitted.
Submit transaction hash
The transaction hash associated with the transaction where the Flag event was emitted can now be submitted!
Last updated