Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

🗃️ create table conditions #40

Merged
merged 5 commits into from
Jan 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
87 changes: 87 additions & 0 deletions alembic/versions/c14c4b6f36b3_create_table_conditions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
"""create-table-conditions

Revision ID: c14c4b6f36b3
Revises: 0894f3022876
Create Date: 2024-01-11 16:02:26.575786

"""
from typing import Sequence, Union

from alembic import op
import sqlalchemy as sa
from sqlalchemy.dialects import postgresql

# revision identifiers, used by Alembic.
revision: str = "c14c4b6f36b3"
down_revision: Union[str, None] = "0894f3022876"
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None


def upgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
op.create_table(
"conditions",
sa.Column("id", sa.UUID(), nullable=False),
sa.Column(
"type",
sa.Enum(
"MAX_CALLS_PER_ENTRYPOINT",
"MAX_CALLS_PER_SPONSEE",
name="conditiontype",
),
nullable=True,
),
sa.Column(
"sponsee_address",
sa.String(),
sa.CheckConstraint(
"(type = 'MAX_CALLS_PER_SPONSEE') = (sponsee_address IS NOT NULL)",
name="sponsee_address_not_null_constraint",
),
nullable=True,
),
sa.Column(
"contract_id",
sa.UUID(),
sa.CheckConstraint(
"(type = 'MAX_CALLS_PER_ENTRYPOINT') = (contract_id IS NOT NULL)",
name="contract_id_not_null_constraint",
),
nullable=True,
),
sa.Column(
"entrypoint_id",
sa.UUID(),
sa.CheckConstraint(
"(type = 'MAX_CALLS_PER_ENTRYPOINT') = (entrypoint_id IS NOT NULL)",
name="entrypoint_id_not_null_constraint",
),
nullable=True,
),
sa.Column("vault_id", sa.UUID(), nullable=False),
sa.Column("max", sa.Integer(), nullable=False),
sa.Column("current", sa.Integer(), nullable=False),
sa.Column("created_at", sa.DateTime(timezone=True), nullable=False),
sa.ForeignKeyConstraint(
["contract_id"],
["contracts.id"],
),
sa.ForeignKeyConstraint(
["entrypoint_id"],
["entrypoints.id"],
),
sa.ForeignKeyConstraint(
["vault_id"],
["credits.id"],
),
sa.PrimaryKeyConstraint("id"),
)
# ### end Alembic commands ###


def downgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
op.drop_table("conditions")
op.execute("DROP type conditiontype")
# ### end Alembic commands ###
9 changes: 5 additions & 4 deletions demo/staking-contract.mligo
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
#import "../permit-cameligo/src/main.mligo" "FA2"

type storage = {
nft_address: address;
staked: (address, nat) big_map;
}
type storage =
{
nft_address : address;
staked : (address, nat) big_map
}

(* We need to provide the address of the NFT's owner so that the transfer can be done by someone
* else (we don't rely on Tezos.get_sender ()) *)
Expand Down
147 changes: 147 additions & 0 deletions src/crud.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from sqlalchemy.orm import Session

from .utils import (
ConditionAlreadyExists,
ContractAlreadyRegistered,
ContractNotFound,
CreditNotFound,
Expand Down Expand Up @@ -308,3 +309,149 @@ def check_calls_per_month(db, contract_id):
return True
nb_operations_already_made = get_operations_by_contracts_per_month(db, contract_id)
return max_calls >= len(nb_operations_already_made)


def create_max_calls_per_sponsee_condition(
db: Session, condition: schemas.CreateMaxCallsPerSponseeCondition
):
# If a condition still exists, do not create a new one
existing_condition = (
db.query(models.Condition)
.filter(models.Condition.sponsee_address == condition.sponsee_address)
.filter(models.Condition.vault_id == condition.vault_id)
.filter(models.Condition.current < models.Condition.max)
.one_or_none()
)
if existing_condition is not None:
raise ConditionAlreadyExists(
"A condition with maximum calls per sponsee already exists and the maximum is not reached. Cannot create a new one."
)
db_condition = models.Condition(
**{
aguillon marked this conversation as resolved.
Show resolved Hide resolved
"type": schemas.ConditionType.MAX_CALLS_PER_SPONSEE,
"sponsee_address": condition.sponsee_address,
"vault_id": condition.vault_id,
"max": condition.max,
"current": 0,
}
)
db.add(db_condition)
db.commit()
db.refresh(db_condition)
return schemas.MaxCallsPerSponseeCondition(
sponsee_address=db_condition.sponsee_address,
vault_id=db_condition.vault_id,
max=db_condition.max,
current=db_condition.current,
type=db_condition.type,
created_at=db_condition.created_at,
id=db_condition.id,
)


def create_max_calls_per_entrypoint_condition(
db: Session, condition: schemas.CreateMaxCallsPerEntrypointCondition
):
# If a condition still exists, do not create a new one
existing_condition = (
db.query(models.Condition)
.filter(models.Condition.entrypoint_id == condition.entrypoint_id)
.filter(models.Condition.contract_id == condition.contract_id)
.filter(models.Condition.vault_id == condition.vault_id)
.filter(models.Condition.current < models.Condition.max)
.one_or_none()
)
if existing_condition is not None:
raise ConditionAlreadyExists(
"A condition with maximum calls per entrypoint already exists and the maximum is not reached. Cannot create a new one."
)
db_condition = models.Condition(
**{
"type": schemas.ConditionType.MAX_CALLS_PER_ENTRYPOINT,
"contract_id": condition.contract_id,
"entrypoint_id": condition.entrypoint_id,
"vault_id": condition.vault_id,
"max": condition.max,
"current": 0,
}
)
db.add(db_condition)
db.commit()
db.refresh(db_condition)
return schemas.MaxCallsPerEntrypointCondition(
contract_id=db_condition.contract_id,
entrypoint_id=db_condition.entrypoint_id,
vault_id=db_condition.vault_id,
max=db_condition.max,
current=db_condition.current,
type=db_condition.type,
created_at=db_condition.created_at,
id=db_condition.id,
)


def check_max_calls_per_sponsee(db: Session, sponsee_address: str, vault_id: UUID4):
return (
db.query(models.Condition)
.filter(models.Condition.type == schemas.ConditionType.MAX_CALLS_PER_SPONSEE)
.filter(models.Condition.sponsee_address == sponsee_address)
.filter(models.Condition.vault_id == vault_id)
.one_or_none()
)


def check_max_calls_per_entrypoint(
db: Session, contract_id: UUID4, entrypoint_id: UUID4, vault_id: UUID4
):
return (
db.query(models.Condition)
.filter(models.Condition.type == schemas.ConditionType.MAX_CALLS_PER_ENTRYPOINT)
.filter(models.Condition.contract_id == contract_id)
.filter(models.Condition.entrypoint_id == entrypoint_id)
.filter(models.Condition.vault_id == vault_id)
.one_or_none()
)


def check_conditions(db: Session, datas: schemas.CheckConditions):
print(datas)
sponsee_condition = check_max_calls_per_sponsee(
db, datas.sponsee_address, datas.vault_id
)
entrypoint_condition = check_max_calls_per_entrypoint(
db, datas.contract_id, datas.entrypoint_id, datas.vault_id
)

# No condition registered
if sponsee_condition is None and entrypoint_condition is None:
return True
# One of condition is excedeed
if (
sponsee_condition is not None
and (sponsee_condition.current >= sponsee_condition.max)
) or (
entrypoint_condition is not None
and (entrypoint_condition.current >= entrypoint_condition.max)
):
return False

# Update conditions
# TODO - Rewrite with list

if sponsee_condition:
update_condition(db, sponsee_condition)
if entrypoint_condition:
update_condition(db, entrypoint_condition)
return True


def update_condition(db: Session, condition: models.Condition):
db.query(models.Condition).filter(models.Condition.id == condition.id).update(
{"current": condition.current + 1}
)


def get_conditions_by_vault(db: Session, vault_id: str):
return (
db.query(models.Condition).filter(models.Condition.vault_id == vault_id).all()
)
62 changes: 61 additions & 1 deletion src/models.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,18 @@
from sqlalchemy import Boolean, Column, DateTime, ForeignKey, Integer, String
from sqlalchemy import (
Boolean,
CheckConstraint,
Column,
DateTime,
Enum,
ForeignKey,
Integer,
String,
)
from sqlalchemy.orm import relationship
from sqlalchemy.dialects.postgresql import UUID
import uuid

from .schemas import ConditionType
from .database import Base
import datetime

Expand Down Expand Up @@ -46,6 +57,7 @@ def __repr__(self):
entrypoints = relationship("Entrypoint", back_populates="contract")
credit = relationship("Credit", back_populates="contracts")
operations = relationship("Operation", back_populates="contract")
conditions = relationship("Condition", back_populates="contract")


# ------- ENTRYPOINT ------- #
Expand All @@ -69,6 +81,7 @@ def __repr__(self):

contract = relationship("Contract", back_populates="entrypoints")
operations = relationship("Operation", back_populates="entrypoint")
conditions = relationship("Condition", back_populates="entrypoint")


# ------- CREDITS ------- #
Expand All @@ -88,6 +101,7 @@ def __repr__(self):

owner = relationship("User", back_populates="credits")
contracts = relationship("Contract", back_populates="credit")
conditions = relationship("Condition", back_populates="vault")


# ------- OPERATIONS ------- #
Expand All @@ -107,3 +121,49 @@ class Operation(Base):

contract = relationship("Contract", back_populates="operations")
entrypoint = relationship("Entrypoint", back_populates="operations")


# ------- CONDITIONS ------- #


class Condition(Base):
__tablename__ = "conditions"

id = Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
type = Column(Enum(ConditionType))
sponsee_address = Column(
String,
quentin-burg marked this conversation as resolved.
Show resolved Hide resolved
CheckConstraint(
"(type = 'MAX_CALLS_PER_SPONSEE') = (sponsee_address IS NOT NULL)",
name="sponsee_address_not_null_constraint",
),
nullable=True,
)
contract_id = Column(
UUID(as_uuid=True),
CheckConstraint(
"(type = 'MAX_CALLS_PER_ENTRYPOINT') = (contract_id IS NOT NULL)",
name="contract_id_not_null_constraint",
),
ForeignKey("contracts.id"),
nullable=True,
)
entrypoint_id = Column(
UUID(as_uuid=True),
CheckConstraint(
"(type = 'MAX_CALLS_PER_ENTRYPOINT') = (entrypoint_id IS NOT NULL)",
name="entrypoint_id_not_null_constraint",
),
ForeignKey("entrypoints.id"),
nullable=True,
)
vault_id = Column(UUID(as_uuid=True), ForeignKey("credits.id"), nullable=False)
max = Column(Integer, nullable=False)
current = Column(Integer, nullable=False)
created_at = Column(
DateTime(timezone=True), default=datetime.datetime.utcnow(), nullable=False
)

contract = relationship("Contract", back_populates="conditions")
entrypoint = relationship("Entrypoint", back_populates="conditions")
vault = relationship("Credit", back_populates="conditions")
Loading
Loading