All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.takamaka.code.tokens.ERC20WithSnapshots Maven / Gradle / Ivy

The newest version!
/*
Copyright 2021 Marco Crosara and Fausto Spoto

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package io.takamaka.code.tokens;

import static io.takamaka.code.lang.Takamaka.event;
import static io.takamaka.code.lang.Takamaka.require;

import io.takamaka.code.lang.Contract;
import io.takamaka.code.lang.Event;
import io.takamaka.code.lang.FromContract;
import io.takamaka.code.lang.View;
import io.takamaka.code.math.UnsignedBigInteger;
import io.takamaka.code.util.StorageMap;
import io.takamaka.code.util.StorageTreeMap;

/**
 * An {@link IERC20} token decorator, that additionally tracks
 * the snapshots performed and makes them accessible by progressive numbers.
 * This mimics the implementation by OpenZeppelin.
 * Note that all tokens are snapshottable in Hotmoka, hence use this class
 * only in the very rare case that you need to explicitly refer to snapshots by number.
 */
public abstract class ERC20WithSnapshots extends Contract implements IERC20 {

	/**
	 * The decorated token.
	 */
	protected final IERC20 parent;
    private final StorageMap _snapshots = new StorageTreeMap<>();
    private UnsignedBigInteger _currentSnapshotId = new UnsignedBigInteger(); // Note: First snapshot has the id 1 -> see snapshot()

    /**
     * Builds a decoration of the given token, to track snapshots and make them
     * accessible by progressive numbers.
     *
     * @param parent the token to decorate
     */
    public @FromContract ERC20WithSnapshots(IERC20 parent) {
    	this.parent = parent;
    }

    /**
     * Emitted when a snapshot identified by {@code id} is created.
     */
    public static class Snapshot extends Event {

    	/**
    	 * The identifier of the snapshot.
    	 */
    	public final UnsignedBigInteger id;

        /**
         * Allows the {@link ERC20WithSnapshots.Snapshot} event to be issued.
         *
         * @param id the id of the created snapshot
         */
        @FromContract Snapshot(UnsignedBigInteger id) {
            this.id = id;
        }

        /**
         * Yields the id of this snapshot.
         * 
         * @return the id of this snapshot
         */
        public final @View UnsignedBigInteger getId() {
        	return id;
        }
    }

    /**
     * Returns the id of the last screenshot that was created.
     *
     * @return the id of the last screenshot
     */
    public final @View UnsignedBigInteger getCurrentSnapshotId() {
        return _currentSnapshotId;
    }

    @Override @FromContract
	public final boolean transfer(Contract recipient, int amount) {
    	return transfer(recipient, new UnsignedBigInteger(amount));
	}

	@Override @FromContract
	public final boolean transfer(Contract recipient, long amount) {
		return transfer(recipient, new UnsignedBigInteger(amount));
	}

    /**
     * Creates a new snapshot and returns its snapshot id.
     * Emits a {@link ERC20WithSnapshots.Snapshot} event that contains the same id.
     *
     * @return id of the created snapshot
     */
    @Override
    public IERC20View snapshot() {
        IERC20View snapshot = parent.snapshot();

        _currentSnapshotId = _currentSnapshotId.next();
        _snapshots.put(_currentSnapshotId, snapshot);

        event(new Snapshot(_currentSnapshotId));

        return snapshot;
    }

    /**
     * Retrieves the balance of {@code account} at the time the snapshot {@code snapshotId} was created.
     *
     * @param account account whose balance is to be retrieved
     * @param snapshotId snapshot from which to recover the balance
     * @return the balance of {@code account} relative to the snapshot {@code snapshotId}
     */
    public final @View UnsignedBigInteger balanceOfAt(Contract account, UnsignedBigInteger snapshotId) {
        return _getSnapshot(snapshotId).balanceOf(account);
    }

    /**
     * Retrieves the total supply at the time the snapshot {@code snapshotId} was created.
     *
     * @param snapshotId snapshot from which to recover the total supply
     * @return the total supply relative to the snapshot {@code snapshotId}
     */
    public final @View UnsignedBigInteger totalSupplyAt(UnsignedBigInteger snapshotId) {
        return _getSnapshot(snapshotId).totalSupply();
    }

    /**
     * Returns the snapshot with the identifier {@code snapshotId}
     *
     * @param snapshotId identifier of the snapshot to be returned
     * @return the snapshot with the identifier {@code snapshotId}
     */
    private @View IERC20View _getSnapshot(UnsignedBigInteger snapshotId) {
        require(snapshotId != null, "the id cannot be null");
        require(snapshotId.signum() > 0, "the id cannot be 0");
        require(snapshotId.compareTo(_currentSnapshotId) <= 0, "non-existent id");

        return _snapshots.getOrDefault(snapshotId, this);
    }

	@Override
	public @View UnsignedBigInteger totalSupply() {
		return parent.totalSupply();
	}

	@Override
	public @View UnsignedBigInteger balanceOf(Contract account) {
		return parent.balanceOf(account);
	}

	@Override
	public @View UnsignedBigInteger allowance(Contract owner, Contract spender) {
		return parent.allowance(owner, spender);
	}

	@Override
	public @View int size() {
		return parent.size();
	}

	@Override
	public @View Contract select(int k) {
		return parent.select(k);
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy