cleaninty is a PC tool used to communicate with Nintendo's SOAP servers. For a 3DS, these servers deal with managing eShop accounts, downloading eShop titles, and system transfers. It is also the tool used for what is informally known as a "SOAP transfer".
Overview
SOAP transfers involve complex functionality. As a result, the following explanation has been divided into two versions: a simplified user-end version, and the technical version.
If you do not care about the technical side of things, you may skip that part, and will still be able to understand how to use cleaninty itself.
There are two pieces of data in a 3DS that let it talk to Nintendo's eShop servers with a unique ID: its serial number and its otp.bin. If these are copied out of the console and used somewhere else, they can be used to imitate the console - meaning Nintendo's servers can act on commands without the console doing anything on its end.
However, the files cannot communicate on their own, and a connection to Nintendo's servers that acts identically to a console is still needed. This is the part cleaninty handles.
The reason this allows for changing eShop regions easily, and at infinite range, are as follows:
Ease of Use: 'Records' of all purchased apps are stored on Nintendo's servers, and some of these records are tied to a separate account that existed before the concept of NNIDs was added - these tickets cannot be removed by normal means, and their presence blocks the console from registering to any other eShop region. (The most common of these tickets is the Mii Plaza 3.x update.) The only way to remove these tickets is to transfer them to another console, and cleaninty is able to move only the legacy account's records by being extremely precise with what commands are and aren't used in the process.
Infinite Range: System transfers are effectively divided into three parts: the local content transfer, the NNID transfer, and the legacy account transfer. The local content transfer is the important part here, as on an actual console, these three must be done at the same time - but if cleaninty sends the commands for a legacy account transfer, it doesn't start the content transfer, and thus the consoles do not have to be next to each other. (Technically, this also means a Movable Moveover is the exact opposite of a SOAP transfer.)
First, some background info: there are two accounts for the eShop.
Legacy DeviceID-based accounts, which were in use starting from the first system version but are mostly unused now.
NNID-based accounts, which were introduced by system firmware v7.0 and remain as the main account type.
Additionally, it should be mentioned that there are four main parts of the 3DS eShop's servers that are related to SOAP operations. Connecting to most of them requires the use of two cerificates from the console(s) to verify it's a real console, those certificates being ClCertA and CTCert. (The needed data from CTCert is stored inside the console's otp.binfrom offsets 0x20 to 0x80.)
ECS: Handles management of NNID accounts and tickets. Requires certificates.
IAS: Handles management of legacy accounts, and has IVS as a sub-service for identity verification (including a stored copy of movable.sed).
CAS: Outputs lists of title metadata, country-related info, and valid currency management options. Requires certificates.
NUS: Downloads of games, updates and system titles. Does not require certificates for system titles, but does require them for games and updates.
NUS and CAS are not relevant to this specifically, but it is worth knowing about them in general.
More detailed information on this subject can be found on this page.
The issue that makes system transfers required at all is that legacy accounts are still used in some specific edge cases, when they shouldn't be.
Specifically, certain titles are not linked to the NNID when purchased/downloaded (the exact cause is still unknown, but a leading theory is that it's because they were delisted from the eShop), and as such, those titles' tickets will instead attach to the legacy account and stay there. The titles that do this will be called legacy titles for the remainder of this explanation.
Since the legacy account is meant to be entirely out of use, legacy titles are far harder to remove than 'normal' ones - an NNID can be moved anywhere with relative ease because ECS just throws ownership over and lets the console do proper region checks later, but IAS has significantly more checks with the legacy account.
Specifically, if there are still titles on the legacy account, then a specific call to IVS to create a new eShop account will fail because it will refuse to mismatch the legacy account's region with its titles.
In this scenario, trying to do a normal system transfer to fix eShop works if done before region changing. But attempting to system transfer after the region change will also fail, because the console(s) detect that they're region changed at the firmware level before it even starts.
And on top of that, the average user does not have a second console to system transfer to in the first place. This is where cleaninty comes in.
Specifically, cleaninty's role is to create a PC-based connection to Nintendo's servers using the same certificates that validate a normal connection, and then give the user extremely fine precision over which commands they do or don't want to use. Additionally, since it only uses the consoles' files and only talks to the servers, the physical consoles do not have to be present for any part of the process.
Using this PC-based connection, it is entirely possible to pick and choose in a very specific way that bypasses normal requirements, using two consoles (the "donor" and "recipient"):
First, the donor must already have a blank legacy account (either through luck or through its own SOAP transfer). This allows it to perform EShopRegionChange freely without restrictions, as there are no legacy titles holding it back.
Once the donor has a blank account, it can EShopRegionChange to match the recipient's eShop account region, and then proceed to take the recipient's account through a SysTransfer.
The reason this works is because when cleaninty does the SysTransfer, the command is run in isolation - so it will not check the consoles' firmware regions, make no requests to ECS, and immediately move the account only after checking they're the same region without touching anything else.
Once the legacy account is moved, the recipient will create a new blank account when it next opens the eShop - and in turn, because the new account is made entirely from scratch, this new account's region will match the console's firmware even if it's region-changed. This gives the 'recipient' working eShop access and the ability to change its own region freely - and as the eShop has closed all new purchases and delisted titles cannot be redownloaded from the eShop, it should not be possible for it to receive legacy titles a second time, meaning this fix is effectively permanent.
Also note that the donor also remains 'free' when this happens, as the transferred legacy titles vanish at some point along the way instead of being properly moved to its account. This means that a donor can be used infinite times, the only limit being the seven-day cooldown between each individual SysTransfer.
Features
When the required constants have been supplied through SetupConstants and you have the unique data (otp.bin and either SecureInfo_A or the serial number) of a console, cleaninty can act as that console and do the following:
GenJson: Compiles the console's data into a single JSON file. This JSON is required for all other commands except RecoverIVS.
CheckReg: Obtains the console's eShop status, eShop region, and any titles attached to its eShop account, then updates the JSON file with the new data.
SysTransfer: Moves the eShop titles of the source console to the target console. This is the only needed command for a SOAP transfer if the console has legacy tickets.
A successful use of this command triggers a 7-day cooldown on system transfers for both consoles, the same as a full system transfer.
NNIDTransfer: (Still experimental. Use with caution.) Moves only the NNIDs of the source console to the target console. This is not affected by system transfer cooldowns and does not trigger a cooldown.
LastTransfer: Provides the date&time of the given console's last system transfer, the number of transfers it has ever done, and the time at which the current transfer cooldown will expire if there is one active.
GetIVS: Downloads the console's stored copy of movable.sed from the SOAP servers, if they have one.
SetIVS: Uploads the chosen JSON's stored movable.sed to the SOAP servers. This will overwrite the current stored movable.
RecoverIVS: Tries to recover a console's movable.sed using only its raw otp.bin and eShop region data.
EShopDelete: Deletes the target console's eShop account. This is the secondary part of a SOAP transfer if the console has no legacy tickets, as the console will then automatically register an account in the correct region when it next accesses the eShop.
EShopRegionChange: Attempts to delete and then recreate the target console's eShop account for the entered region. This is the main part of a SOAP transfer if the console has no legacy tickets, but an EShopDelete should still be done afterward.
ETickets/ETicketDownload/ETikTitleDownload: Lists all owned eShop tickets / downloads all tickets / downloads the titles attached to all tickets, respectively, from the given console's eShop account.
Installation
Instructions for installation & setup are on the GitHub page, but the installation instructions may need to be interpreted for your OS.
Regardless of your OS, you will need a 3DS with both custom firmware and GodMode9 installed to dump all of the files required to do SetupConstants. The vast majority of them are dumped using ExtractSystemElements.gm9, but the the AES Constant "C" is found using the full set of instructions on this page.
The AES Constant, along with all other constants used by cleaninty, are copyrighted data. Obtaining them from your own console(s) is fine, but do not share the constants with anyone else.
These constants are the same on all consoles. Once one set is dumped, you will not need to redump in the future unless you lose access to them.
Windows
Don't bother trying to install cleaninty on Windows directly. Windows has OpenSSL disabled in its curl.exe, but cleaninty requires OpenSSL to function. Working around this issue manually is obnoxious and not worth the time spent.
Instead, there are two options:
Install a Linux distro through WSL and then install cleaninty inside the WSL instance using the macOS/Linux instructions. (This is the simpler path, and WSL is useful for many other things. If you choose this instead of msys2, it is recommended that you also install the Windows Terminal.)
Install msys2 and then install cleaninty inside the msys2 instance using the below instructions.
To install cleaninty inside msys2, open the terminal mingw64.exe that is inside the msys2 installation folder, then run the following two commands one at a time:
Once this is completed, from here on out you will need to open the msys2 mingw64.exe terminal to use cleaninty.
Be aware that when using cleaninty through msys2, the place it will look in to find boot9.bin, SSLCertificates, and ctr_constants.json is a folder named 3ds inside your msys2 home folder.
macOS and Linux
First, ensure you have Python 3.7 or newer. You can check if your Python version is new enough by opening a terminal and running the command python3 --version. If you do not, install a compatible version from either your package manager or the Python website.
Then, either install cleaninty directly from pip or clone its repo via the command git clone https://github.com/luigoalma/cleaninty.git and then run the setup.py script.
Usage
Make sure the files for all consoles you compile into a json are accurate before using them in cleaninty, or else the commands may affect a different console than they "should be" affecting (or simply fail outright).
The easiest way to do this is by checking the serial sticker(s) on the console against the copy of the serial in SecureInfo_A.
If none of the stickers agree with the SecureInfo, also check against the copy in inspect.log and make sure its listed MAC Address matches the one within firmware by booting the console normally and going into System Settings -> Internet Settings -> Other Information -> Confirm MAC Address.
There is no graphical interface for cleaninty. All commands are ran through the command line.
Manual command line
The commands are the same on all operating systems. Run cleaninty ctr (command) --help for information on an individual command's syntax.
As an example, the minimum list of commands needed to set up two consoles' data and perform a SOAP transfer between them would be as follows:
Although this script is far simpler to use than manually inputting commands, errors may still occur during edge cases. Knowledge of the command line will still likely be required to debug if this occurs.
If you are inexperienced with the command line or just don't want to type the commands manually every time, there is a SOAP bash script made by StarlitSkies that heavily simplifies the process.
Read the instructions on its page for setup and usage.