/ basic_bank / src / main.adl
main.adl
  1  program basic_bank.alpha {
  2      // A token, issued by a bank.
  3      // - 'owner'  : The address of the account that owns the record associated with this token.
  4      // - 'amount' : The amount of tokens owned by the account.
  5      record Token {
  6          owner: address,
  7          amount: u64,
  8      }
  9  
 10      // An on-chain mapping, storing the amount of tokens owned by each account
 11      // The account is stored as a hash to preserve user privacy.
 12      mapping balances: field => u64;
 13  
 14      // Returns a new Token.
 15      // - `owner` : The address of the account to issue the token to.
 16      // - `amount`: The amount of tokens to issue.
 17      // Requires that the function caller is the bank.
 18      // The bank's address is ax12mq8xts3wh22vuuup4nwysxhfgpm43cqmkh279exetljag58v5qqc4suk3.
 19      transition issue(owner: address, amount: u64) -> Token {
 20          assert_eq(self.caller, ax12mq8xts3wh22vuuup4nwysxhfgpm43cqmkh279exetljag58v5qqc4suk3);
 21          return Token {
 22              owner: owner,
 23              amount: amount,
 24          };
 25      }
 26  
 27      // Deposits some amount of money into the bank.
 28      // Returns a new Token with the remaining amount of money.
 29      // - `token` : A record containing tokens to deposit.
 30      // - `amount`: The amount of tokens to deposit.
 31      async transition deposit(token: Token, amount: u64) -> (Token, Future) {
 32          let difference: u64 = token.amount - amount;
 33  
 34          let remaining: Token = Token {
 35              owner: token.owner,
 36              amount: difference,
 37          };
 38  
 39          // Compute the hash of the token owner.
 40          let hash: field = BHP256::hash_to_field(token.owner);
 41  
 42          return (remaining, finalize_deposit(hash, amount));
 43      }
 44  
 45      // Updates on-chain state by the amount of tokens deposited.
 46      // - `hash`  : The hash of the token owner.
 47      // - `amount`: The amount of tokens that were deposited.
 48      async function finalize_deposit(hash: field, amount: u64) {
 49          let current_amount: u64 = Mapping::get_or_use(balances, hash, 0u64);
 50          Mapping::set(balances, hash, current_amount + amount);
 51      }
 52  
 53      // Returns a new Token containing the amount of money withdrawn.
 54      // - `recipient`: The address of the account to withdraw the tokens to.
 55      // - `amount`   : The amount of tokens to withdraw.
 56      // - `rate`     : The compound interest rate.
 57      // - `periods`  : The number of periods to compound the interest over.
 58      // Requires that the function caller is the bank.
 59      async transition withdraw(recipient: address, amount: u64, rate: u64, periods: u64) -> (Token, Future) {
 60          assert_eq(self.caller, ax12mq8xts3wh22vuuup4nwysxhfgpm43cqmkh279exetljag58v5qqc4suk3);
 61          let hash: field = BHP256::hash_to_field(recipient);
 62  
 63          let total: u64 = calculate_interest(amount, rate, periods);
 64  
 65          let token: Token = Token {
 66              owner: recipient,
 67              amount: total,
 68          };
 69  
 70          return (token, finalize_withdraw(hash, amount));
 71      }
 72  
 73      // Updates on-chain state by the amount of tokens withdrawn.
 74      // - `hash`  : The hash of the token owner.
 75      // - `amount`: The amount of tokens that were withdrawn.
 76      async function finalize_withdraw(hash: field, amount: u64) {
 77          let current_amount: u64 = Mapping::get_or_use(balances, hash, 0u64);
 78          Mapping::set(balances, hash, current_amount - amount);
 79      }
 80  
 81      // Returns the total amount of tokens after compounding interest.
 82      // - `principal`: The amount of tokens to compound interest over.
 83      // - `rate`     : The compound interest rate.
 84      // - `periods`  : The number of periods to compound the interest over.
 85      function calculate_interest(principal: u64, rate: u64, periods: u64) -> u64 {
 86          let amount: u64 = principal;
 87  
 88          for i:u64 in 0u64..100u64 {
 89              if i < periods {
 90                  amount += (amount * rate) / 10000u64;
 91              }
 92          }
 93  
 94          return amount;
 95      }
 96  
 97      // The constructor is configured to prevent upgrades.
 98      @noupgrade
 99      async constructor() {}
100  }