Token Balance

Falsify your token balance.

Please log in
Difficulty: Intermediate
User avatar

Author

One of your favorite token projects tries to keep track of all its users’ token balances in their smart contract.

Unfortunately, they hired bluesign as their smart contract engineer who left a way to falsify your balance.

Find a way to make the balances dictionary return more than what is in your actual vault.

Below is the contract and script used to pass the level.

cadence
		
			import FungibleToken from "./FungibleToken.cdc"

pub contract ExampleToken: FungibleToken {

    pub var totalSupply: UFix64
    access(self) let balances: {Address: UFix64}

    pub let VaultStoragePath: StoragePath
    pub let VaultPublicPath: PublicPath
    pub let ReceiverPublicPath: PublicPath

    pub event TokensInitialized(initialSupply: UFix64)
    pub event TokensWithdrawn(amount: UFix64, from: Address?)
    pub event TokensDeposited(amount: UFix64, to: Address?)
    pub event TokensMinted(amount: UFix64)
    pub event TokensBurned(amount: UFix64)

    pub resource Vault: FungibleToken.Provider, FungibleToken.Receiver, FungibleToken.Balance {

        pub var balance: UFix64

        pub fun withdraw(amount: UFix64): @FungibleToken.Vault {
            self.balance = self.balance - amount
            if let owner: Address = self.owner?.address {
                emit TokensWithdrawn(amount: amount, from: owner)
                ExampleToken.balances[owner] = self.balance
            }
            return <- create Vault(balance: amount)
        }

        pub fun deposit(from: @FungibleToken.Vault) {
            let vault <- from as! @Vault
            self.balance = self.balance + vault.balance
            if let owner: Address = self.owner?.address {
                emit TokensDeposited(amount: vault.balance, to: owner)
                ExampleToken.balances[owner] = self.balance
            }
            vault.balance = 0.0
            destroy vault
        }

        init(balance: UFix64) {
            self.balance = balance
        }

        destroy() {
            pre {
                self.balance == 0.0: "Cannot destroy a Vault unless balance is 0."
            }
        }
    }

    pub fun createEmptyVault(): @Vault {
        return <- create Vault(balance: 0.0)
    }

    pub fun mintTokens(amount: UFix64): @Vault {
        pre {
            amount > 0.0: "Amount minted must be greater than zero"
        }
        ExampleToken.totalSupply = ExampleToken.totalSupply + amount
        emit TokensMinted(amount: amount)
        return <- create Vault(balance: amount)
    }

    pub fun getBalances(): {Address: UFix64} {
        return self.balances
    }

    init() {
        self.totalSupply = 0.0
        self.balances = {}

        self.VaultStoragePath = /storage/ExampleTokenVault
        self.VaultPublicPath = /public/ExampleTokenMetadata
        self.ReceiverPublicPath = /public/ExampleTokenReceiver

        emit TokensInitialized(initialSupply: self.totalSupply)
    }
}
		 
	
cadence
		
			import ExampleToken from "./ExampleToken.cdc"
import FungibleToken from "./FungibleToken.cdc"

pub fun main(user: Address): Bool {
    let vault = getAccount(user).getCapability(ExampleToken.VaultPublicPath)
                    .borrow<&ExampleToken.Vault{FungibleToken.Balance}>()
                    ?? panic("The Vault does not exist in the user's storage.")

    return ExampleToken.getBalances()[user]! > vault.balance
}