Table of Contents generated with DocToc

IOTA Move CTF Progress (Challenges 0-8)

Date updated: March 2, 2026
Network: IOTA Testnet
Wallet: 0x7ac899c7920ecde96c92785bf3e81a3965b03b7378ab02feab70905e358ec702

This document is my personal run log for the IOTA Move CTF.
For each challenge, I link the official docs page, summarize what I did, and record the on-chain proof (tx digest + flag object).


Challenge 0: Mint Leap Frog NFT

Official docs: https://docs.iota.org/developer/iota-move-ctf/challenge_0

What I did:

  • I called the challenge package function to mint the NFT to my address.
  • I verified the created object fields (name, description, url) in CLI.

Result:

  • Tx: D1ceDXhD6GXe6nmY1z8TN2LaAtsRtk5gyvvmWqVUg3BX
  • Created object: 0x137b9582f3cc4774aea57ab6a69e1867a57b0f061a49290d45ef8ac605f195d3

Explorer:

  • https://testnet.iotascan.com/txblock/D1ceDXhD6GXe6nmY1z8TN2LaAtsRtk5gyvvmWqVUg3BX
  • https://testnet.iotascan.com/object/0x137b9582f3cc4774aea57ab6a69e1867a57b0f061a49290d45ef8ac605f195d3

Challenge 1: Checkin

Official docs: https://docs.iota.org/developer/iota-move-ctf/challenge_1

What I did:

  • I called checkin::get_flag with no arguments.
  • I verified that the on-chain Flag.user field was my sender address.

Result:

  • Tx: HHhP5sWPQYHUWRkYWN7FxS3GSGJn35ZFtD1nRJZ8G5Ua
  • Flag object: 0x4fae16349410f11d77a22baf6f992c40983eb00c052a87071c57c275419f6c97

Explorer:

  • https://testnet.iotascan.com/txblock/HHhP5sWPQYHUWRkYWN7FxS3GSGJn35ZFtD1nRJZ8G5Ua
  • https://testnet.iotascan.com/object/0x4fae16349410f11d77a22baf6f992c40983eb00c052a87071c57c275419f6c97

Challenge 2: Lucky Number

Official docs: https://docs.iota.org/developer/iota-move-ctf/challenge_2

What I did:

  • I read the source and confirmed lucky_num is effectively ignored.
  • I called luckynumber::get_flag with the shared counter and a u64 value.
  • I verified the counter increment and the created Flag object.

Result:

  • Tx: 3R4BpYk3VJoFD3jUJJtwGfwob6EPPat4TrjHcszjYc9j
  • Flag object: 0x4f5c3802d7a251797adb7c1d2222414f4f31620f518c044849e3a99ae76074bb

Explorer:

  • https://testnet.iotascan.com/txblock/3R4BpYk3VJoFD3jUJJtwGfwob6EPPat4TrjHcszjYc9j
  • https://testnet.iotascan.com/object/0x4f5c3802d7a251797adb7c1d2222414f4f31620f518c044849e3a99ae76074bb

Challenge 3: MintCoin Mechanics

Official docs: https://docs.iota.org/developer/iota-move-ctf/challenge_3

What I did:

  • I read mintcoin::get_flag and saw it requires Coin<MINTCOIN> with exact value 5.
  • I minted three MINTCOIN coins (2 + 2 + 2), merged, then split to produce a 5 coin.
  • I called get_flag with the shared counter and that 5 coin.

Result:

  • Final tx: DEcF4T2RLPmpdA199nzvcofBNw8DoBsmvhtqdSdxJikQ
  • Flag object: 0x2a64d16cc47837b150b3bd99e62b1be6e1c3060d3e30c62a902db8a8125312cd

Explorer:

  • https://testnet.iotascan.com/txblock/DEcF4T2RLPmpdA199nzvcofBNw8DoBsmvhtqdSdxJikQ
  • https://testnet.iotascan.com/object/0x2a64d16cc47837b150b3bd99e62b1be6e1c3060d3e30c62a902db8a8125312cd

Challenge 4: Airdrop

Official docs: https://docs.iota.org/developer/iota-move-ctf/challenge_4

What I did:

  • I read the logic and confirmed each address can only call airdrop once.
  • Because get_flag needs a coin with value 2, I created a second local address, funded it, and claimed once from each address.
  • I transferred the second AIRDROP coin to my main address, merged 1 + 1 -> 2, then called get_flag.

Result:

  • Final tx: GB9w6DiN8Km1VLE6hNk4xSgaUKhKMMXr5qcAmKi4e6zC
  • Flag object: 0xde17cdc6cb42d4655ecc805bdf38e69c61ec5b1930986b9a21d7c4cda602798d

Explorer:

  • https://testnet.iotascan.com/txblock/GB9w6DiN8Km1VLE6hNk4xSgaUKhKMMXr5qcAmKi4e6zC
  • https://testnet.iotascan.com/object/0xde17cdc6cb42d4655ecc805bdf38e69c61ec5b1930986b9a21d7c4cda602798d

Challenge 5: Perfect Pizza

Official docs: https://docs.iota.org/developer/iota-move-ctf/challenge_5

What I did:

  • I decoded the required BCS bytes in get_flag into u16 field values (little-endian):
    • 10, 3, 610, 370, 18, 200, 180, 0
  • I called cook with exactly those values.
  • I called get_flag with the resulting PizzaBox.

Result:

  • Final tx: 7Hqk5cYfRiJUL8FGh7J9pKHbJyxqgd8nWhRAcFWpmTET
  • Flag object: 0x65f06fe985ed0f1c002df150b1a8cbc07fc8230403b4d25d5070c01466b29edd

Explorer:

  • https://testnet.iotascan.com/txblock/7Hqk5cYfRiJUL8FGh7J9pKHbJyxqgd8nWhRAcFWpmTET
  • https://testnet.iotascan.com/object/0x65f06fe985ed0f1c002df150b1a8cbc07fc8230403b4d25d5070c01466b29edd

Challenge 6: Go Recycle!

Official docs: https://docs.iota.org/developer/iota-move-ctf/challenge_6

What I did:

  • I read accept_box and get_flag and confirmed I needed to recycle more than 2 boxes.
  • I cooked 3 new pineapple boxes, transferred each box to the recycler object (transfer-to-object), then called accept_box 3 times using Receiving<PizzaBox>.
  • I called get_flag after my recycle points were above the threshold.

Result:

  • Final tx: J2RwxqK3ZA3VcdnoYmqCL1rb3937L2fXSKtnkiLt2LQY
  • Flag object: 0xbebb5a5744d8ec88bc4c60c70d9e63ae6a6ce6465f27f93e337235851523126e

Explorer:

  • https://testnet.iotascan.com/txblock/J2RwxqK3ZA3VcdnoYmqCL1rb3937L2fXSKtnkiLt2LQY
  • https://testnet.iotascan.com/object/0xbebb5a5744d8ec88bc4c60c70d9e63ae6a6ce6465f27f93e337235851523126e

Challenge 7: PTBs

Official docs: https://docs.iota.org/developer/iota-move-ctf/challenge_7

What I did:

  • I solved this in one PTB:
    1. get_ingredients
    2. make_dough ingredients.0 ingredients.1 ingredients.2 ingredients.3
    3. get_flag dough
  • This uses PTB result binding and nested result indexing.

Result:

  • Final tx: 6ZJB2R6m5rmiz3QbDkYiKq2Gu5eoyJdJNk9XHmtoChiJ
  • Flag object: 0x30cb533c2f95cd6d627f0d4688d6c00e42f87cedb1898ee1e3cb4169b667e48a

Explorer:

  • https://testnet.iotascan.com/txblock/6ZJB2R6m5rmiz3QbDkYiKq2Gu5eoyJdJNk9XHmtoChiJ
  • https://testnet.iotascan.com/object/0x30cb533c2f95cd6d627f0d4688d6c00e42f87cedb1898ee1e3cb4169b667e48a

Challenge 8: Flash!

Official docs: https://docs.iota.org/developer/iota-move-ctf/challenge_8

What I did:

  • I analyzed vault.move and found the flash-loan sequence lets me call get_flag mid-PTB while vault balances are temporarily drained.
  • I discovered the active shared vault object via RPC transaction query:
    • 0xb20dd806796441944552112b3ab9ff1879b623482014e23b398bb0ad8496b8e7
  • In one PTB, I executed:
    1. flash(..., amount=100, a_to_b=false)
    2. get_flag(...) while vault balances satisfy the check
    3. repay_flash(...) so the full transaction still succeeds

Result:

  • Final tx: 97cggbTZ4JUbAa26SNTfxae1im3WBfHYT3676Xb3u7Bn
  • Flag object: 0x85705dad66e517b60c868912799594ebe1404cc4d1b1480e3df272fac49615cc

Explorer:

  • https://testnet.iotascan.com/txblock/97cggbTZ4JUbAa26SNTfxae1im3WBfHYT3676Xb3u7Bn
  • https://testnet.iotascan.com/object/0x85705dad66e517b60c868912799594ebe1404cc4d1b1480e3df272fac49615cc

Index of Official Challenge Pages

  • Introduction: https://docs.iota.org/developer/iota-move-ctf/introduction
  • Challenge 0: https://docs.iota.org/developer/iota-move-ctf/challenge_0
  • Challenge 1: https://docs.iota.org/developer/iota-move-ctf/challenge_1
  • Challenge 2: https://docs.iota.org/developer/iota-move-ctf/challenge_2
  • Challenge 3: https://docs.iota.org/developer/iota-move-ctf/challenge_3
  • Challenge 4: https://docs.iota.org/developer/iota-move-ctf/challenge_4
  • Challenge 5: https://docs.iota.org/developer/iota-move-ctf/challenge_5
  • Challenge 6: https://docs.iota.org/developer/iota-move-ctf/challenge_6
  • Challenge 7: https://docs.iota.org/developer/iota-move-ctf/challenge_7
  • Challenge 8: https://docs.iota.org/developer/iota-move-ctf/challenge_8