1Money implements an Account Model (vs UTXO) for its ledger, where, aside from asset positions, also contains properties governing different issuance functions. Account types include:
Account Types
StateAccount
StateAccount represents a standard user account that can participate in regular transactions.
Key Properties:
Nonce: A counter that increments with each transaction to prevent replay attacks
Use Cases:
Serving as the base account type for users to manage their token holdings
MintAccount
Mint accounts are specialized accounts that control the creation and management of tokens in the system. They represent the authority over a specific token type.
Key Properties:
Nonce: A counter for transaction sequencing
Token metadata and configuration
Authority information
Use Cases:
Creating new tokens
Minting additional token supply
Managing token authorities
Updating token metadata
Pausing/unpausing token transfers
TokenAccount
TokenAccount represents an account that holds a specific token type. It tracks the ownership and balance of tokens for a particular user.
You should be able to derive your token account based on your state account and mint account
Key Properties:
Mint: Address of the mint that issued this token
Amount: The token balance
Owner: Address of the account that owns these tokens
Use Cases:
Holding token balances
Transferring tokens between users
Tracking token ownership
Sample code of Typescript how to derive token account from state account and mint account
import { keccak256, hexToBytes, stringToBytes, bytesToHex } from 'viem';
export type Address = `0x${string}`;
/**
* Derives the token account address given the wallet address and mint address.
*
* Address is 20 byte, 160 bits. Let's say if we want to support 50 billion
* accounts on 1money. That's about 36 bits. There are 124 bits remaining. In
* other words, the collision probability is 1/2^124, which is very very low.
* So, we will be fine to just use the hash of the wallet address and mint
* address to derive the token account address.
*
* @param walletAddress - The wallet address (20 bytes)
* @param mintAddress - The mint address (20 bytes)
* @returns The derived token account address
*/
export function deriveTokenAddress(
walletAddress: string,
mintAddress: string,
): Address {
const walletBytes: Uint8Array = walletAddress.startsWith('0x')
? hexToBytes(walletAddress as Address)
: stringToBytes(walletAddress);
const mintBytes: Uint8Array = mintAddress.startsWith('0x')
? hexToBytes(mintAddress as Address)
: stringToBytes(mintAddress);
const combined = new Uint8Array(walletBytes.length + mintBytes.length);
combined.set(walletBytes, 0);
combined.set(mintBytes, walletBytes.length);
const hashHex = keccak256(combined);
const hashBytes = hexToBytes(hashHex);
const addressBytes = hashBytes.slice(12);
return bytesToHex(addressBytes) as Address;
}
Sample code of Go how to derive token account from state account and mint account
import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
)
// DeriveTokenAccountAddress derives the token account address given the wallet address and mint address.
//
// Address is 20 byte, 160 bits. Let's say if we want to support 50 billion
// accounts on 1money. That's about 36 bits. There are 124 bits remaining. In
// other words, the collision probability is 1/2^124, which is very very low.
// So, we will be fine to just use the hash of the wallet address and mint
// address to derive the token account address.
func DeriveTokenAccountAddress(walletAddress common.Address, mintAddress common.Address) common.Address {
// Concatenate wallet address and mint address bytes
buf := append(walletAddress.Bytes(), mintAddress.Bytes()...)
// Calculate keccak256 hash
hash := crypto.Keccak256(buf)
// Return the last 20 bytes of the hash as the token account address
return common.BytesToAddress(hash[12:])
}