Back to glossary

Rebase Token (Vyper Code Example)

Table of Contents

Example of a Vyper rebase token.

# pragma version ^0.4.0

# Rebase token (compound interest rate)

RAY: constant(uint256) = 10**27
MIN_R: constant(uint256) = 10**25

authorized: public(HashMap[address, bool])
pie: public(uint256)
slices: public(HashMap[address, uint256])
rate: public(uint256)
acc: public(uint256)
t: public(uint256)

@deploy
def __init__():
    self.authorized[msg.sender] = True
    self.rate = RAY
    self.acc = RAY
    self.t = block.timestamp

@external
def set_rate(ray: uint256):
    assert self.authorized[msg.sender]
    assert self.t == block.timestamp
    self.rate = ray

@internal
@view
def r() -> uint256:
    n: uint256 = (block.timestamp - self.t)
    if n > 0:
        rate: uint256 = self.rate
        if rate > RAY:
            # rate = 1 + x
            x: uint256 = rate - RAY
            # binomial expansion
            # (1+x)^n = 1 + n*x + (n*(n-1)/2*x^2) + (n*(n-1)*(n-2)/(2*3)*x^3) + ...
            x1: uint256 = n * x
            x2: uint256 = x1 * ((n - 1) if n > 1 else 0) // 2 * x // RAY
            x3: uint256 = x2 * ((n - 2) if n > 2 else 0) // 3 * x // RAY
            return RAY + x1 + x2 + x3
        elif rate < RAY:
            # rate = 1 - x
            x: uint256 = RAY - rate
            # binomial expansion
            # (1-x)^n = 1 - n*x + (n*(n-1)/2*x^2) - (n*(n-1)*(n-2)/(2*3)*x^3) + ...
            x1: uint256 = n * x
            x2: uint256 = x1 * ((n - 1) if n > 1 else 0) // 2 * x // RAY
            x3: uint256 = x2 * ((n - 2) if n > 2 else 0) // 3 * x // RAY
            # Check underflow and min
            # RAY - x1 + x2 - x3 <= MIN_R
            if RAY + x2 < MIN_R + x1 + x3:
                return MIN_R
            return RAY - x1 + x2 - x3
        else:
            return RAY
    return RAY

@internal
@view
def a() -> uint256:
    return self.acc * self.r() // RAY

@external
@view
def total_supply() -> uint256:
    return self.pie * self.a() // RAY

@external
@view
def balance_of(usr: address) -> uint256:
    return self.slices[usr] * self.a() // RAY

@external
def poke():
    self.acc *= self.r() // RAY
    self.t = block.timestamp

@external
def mint(dst: address, amt: uint256):
    assert self.authorized[msg.sender]
    assert self.t == block.timestamp
    a: uint256 = self.acc
    s: uint256 = amt * RAY // a
    assert s > 0
    self.slices[dst] += s
    self.pie += s

@external
def burn(amt: uint256):
    if amt == max_value(uint256):
        self.pie -= self.slices[msg.sender]
        self.slices[msg.sender] = 0
    else:
        assert self.t == block.timestamp
        a: uint256 = self.acc
        s: uint256 = amt * RAY // a
        assert s > 0
        self.pie -= s
        self.slices[msg.sender] -= s

@external
def transfer(dst: address, amt: uint256):
    if amt == max_value(uint256):
        self.slices[dst] += self.slices[msg.sender]
        self.slices[msg.sender] = 0
    else:
        assert self.t == block.timestamp
        a: uint256 = self.acc
        s: uint256 = amt * RAY // a
        self.slices[msg.sender] -= s
        self.slices[dst] += s

Related Terms

No items found.