# Example Simple Token

Using the knowledge from [developing-your-own-contract](https://docs.lambdaprotocol.io/developers/developing-your-own-contract "mention") let us showcase a really simple token contract and walk you through it.

First lets define which functionality our simple token has

* mint
* transfer
* balance

*mint* and *transfer* should be mutations; and *balance* should be a query to check it via an API call anytime you want

#### Security considerations

Now is a good moment to think about security regarding the 3 functions

**mint**\
only possible to mint once

**transfer**\
you must not be able to transfer more than you have

**balance**\
what do we return if the user has not yet interacted with the contract, has no balance

This is what a final contract could look like, making use of most APIs. Lets go over it

```typescript
import { Contract, ContractParams } from "./types/contract.ts";
import { zUtils } from "./utils/zod.ts";
import { z } from "zod";
import { argsParsing } from "./utils/args-parsing.ts";
import { ExecutionError } from "./types/execution-error.ts";

export default class SimpleToken implements Contract {
  activeOn = 850000;

  private _alreadyMinted = false;
  private _balances = new Map<string, bigint>();

  mint({ metadata, args, eventLogger }: ContractParams) {
    const schema = z.tuple([zUtils.bigint()]);
    const [supply] = argsParsing(schema, args, "mint");

    // safety check to make sure you can only mint once
    if (this._alreadyMinted) throw new ExecutionError("mint: already minted");
    
    // mint the tokens
    this._balances.set(metadata.sender, supply);
    
    // make sure you can only mint once
    this._alreadyMinted = true;

    eventLogger.log({
      type: "MINT",
      message: `${metadata.sender} minted ${supply}`,
    });
  }

  transfer({ metadata, args, eventLogger }: ContractParams) {
    const schema = z.tuple([z.string(), zUtils.bigint()]);
    const [to, value] = argsParsing(schema, args, "transfer");

    // must not send more than you have
    const fromBalance = this._balances.get(metadata.sender) ?? 0n;
    if (fromBalance < value) {
      throw new ExecutionError("transfer: not enough balance");
    }

    // update balances
    this._balances.set(metadata.sender, fromBalance - value);
    const toBeforeBalance = this._balances.get(to) ?? 0n;
    this._balances.set(to, toBeforeBalance + value);

    eventLogger.log({
      type: "TRANSFER",
      message: `transferred from ${
        metadata.sender
      } to ${to} value ${value.toString()}`,
    });
  }

  balance({ args }: ContractParams): bigint {
    const schema = z.tuple([z.string()]);
    const [from] = argsParsing(schema, args, "balance");
    return this._balances.get(from) ?? 0n;
  }
}

```

We follow the Contract architecture by having mutations and queries. `activeOn: 850000` makes the contract active at block 850000, this must be in the future.

Lets start with the properties

### Properties

```typescript
private _alreadyMinted = false;
private _balances = new Map<string, bigint>();
```

`_alreadyMinted` keeps track if we have already minted, to make sure we can only do it once

`_balances` maps the wallet / contract to a balance. We use bigint for this to handle big numbers

now mutations

### Mint

```typescript
mint({ metadata, args, eventLogger }: ContractParams) {
```

for minting we use `metadata`, `args` and `eventLogger` from the parameters we get injected.

```typescript
const schema = z.tuple([zUtils.bigint()]);
const [supply] = argsParsing(schema, args, "mint");
```

this is basically a must, validate the arguments, otherwise you could run into strange problems later on. We prefer using zod for this and built the `argsParsing` utility to help you do this

```typescript
// safety check to make sure you can only mint once
if (this._alreadyMinted) throw new ExecutionError("mint: already minted");
```

This is the security consideration from above, we check the state of the contract to make sure we didn't mint yet

```typescript
// mint the tokens
this._balances.set(metadata.sender, supply);
```

only if it is not yet minted, we use the validated arguments and save the amount to the the balances map.

```typescript
// make sure you can only mint once
this._alreadyMinted = true;
```

Don't forget to store the minted value, otherwise the earlier check is always false and we can mint more than once.

```typescript
eventLogger.log({
    type: "MINT",
    message: `${metadata.sender} minted ${supply}`,
});
```

Now for good practice, log the mint event to be visible later to other users checking the transaction

That's it for the minting part. Really simple

### Transfer

```typescript
const schema = z.tuple([z.string(), zUtils.bigint()]);
const [to, value] = argsParsing(schema, args, "transfer");
```

same as for the mint, we validate the arguments and name them

```typescript
// must not send more than you have
const fromBalance = this._balances.get(metadata.sender) ?? 0n;
if (fromBalance < value) {
  throw new ExecutionError("transfer: not enough balance");
}
```

this is the security consideration from above, we must not transfer more than we have. Therefore we check our balances map for the sender. Fallback is just `0`. If the balance is smaller than the value we are trying to send, we throw an `ExecutionError`

```typescript
// update balances
this._balances.set(metadata.sender, fromBalance - value);
const toBeforeBalance = this._balances.get(to) ?? 0n;
this._balances.set(to, toBeforeBalance + value);
```

after this check is successful, it is only a matter of updating the balances for sender and receiver

```typescript
eventLogger.log({
  type: "TRANSFER",
  message: `transferred from ${
    metadata.sender
  } to ${to} value ${value.toString()}`,
});
```

For good measure, we log again what happened

Simple as this! :thumbsup:

Only thing left is the `balance` query

### Balance

```typescript
balance({ args }: ContractParams): bigint {
    const schema = z.tuple([z.string()]);
    const [from] = argsParsing(schema, args, "balance");
    return this._balances.get(from) ?? 0n;
}
```

here we only need the `args` to read the balance from the balance map and return it
