---
# System prepended metadata

title: Tact Conceptual Issues

---

# Tact Conceptual Issues

Q1: как программист поймет что seqno не будет сохранен без явного commit?

```
actor Wallet {
  var seqno: Uint32

  action something(self: Self) {
    self.seqno = self.seqno + 1;
    thrown(30); // self.seqno == ???
  }
}
```

A1: Неявный commit() после каждого изменения

- ожидаемо с т.з. программистов
- это неправильно с т.з. логики контракта

A2: Возвращать стейт явно

- 
- 

A3: 




```
union ContractMessage { 
    @discriminator(0x467c7, 32)
    case TransferMessage
    ...
}
fn main(mes: InternalMessage[ContractMessage]) {
    verify(mes.seqno != 0).or_throw(10);
    let contract: ContractState = load_state();
    switch (mes.body) {
        case TransferMessage msg => {
            contract.transfer(msg);
        }
        case ChangeOwner msg => { 
            contract.change_owner(msg); 
        }
    }
}
fn transfer(msg: TranferMessage) {
    ...
}
fn change_owner(msg: ChangeOwner) {
    ...
}

------







------

union MyMsg {
    case A;
    case B;
}

actor Wallet {
    
    fn precondition(msg: MyMsg) { // what type ????
        verify(mes.seqno != 0).or_throw(10);
    }
    
    fn transfer(body: TransferMessage)
    fn transfer(body: TransferMessage, info: CommonMsgInfo)
    fn transfer(body: TransferMessage, info: CommonMsgInfo, raw_msg: RawMessage)
    {
        ...
    }
    
    @prefix(0x11223344)
    fn change_owner(c: C, d: D) {
        ...
    }

}




------

union ContractMessage { 
    @discriminator(0x467c7, 32)
    case TransferMessage
    ...
}
fn main(msg: ContractMessage) {
        
    precondition(msg);
    
    route (msg) {
        TransferMessage1 -> transfer,
        TransferMessage2 -> transfer2,
        ChangeOwner -> change_owner,
    }

    postcondition();
}

fn transfer(msg: TranferMessage) {
    ...
}

fn change_owner(msg: ChangeOwner) {
    ...
}



------


fn verify_seqno() { verify(mes.seqno != 0).or_throw(10); }
actor Wallet {

  action transfer(msg: TranferMessage) {
    ...
  }
  action change_owner(msg: ChangeOwner) {
    ...
  }
}

------------

fn main(mes: InternalMessage[ContractMessage, sender=SenderImpl]) {
    ...
}
fn main(mes: InternalMessage[ContractMessage, sender=Actor[SenderMsg]]) {
    ...
}

fn main(state: ContractState, mes: InternalMessage[ContractMessage]) -> ContractState {
    ...
}
```



Wallet V3

```
struct MsgBody {
  val subwallet: Uint32
  val valid_until: Uint32
  val seqno: Uint32

  @derive impl Deserialize {}
}

struct WalletState {
  val seqno: Uint32
  val subwallet: Uint32
  val public_key: Uint256

  @derive impl Deserialize {}
  @derive impl Serialize {}
}

struct NextMessage {
  val cell: RefCell
  val flags: SendRawMsgFlags
  
  @derive impl Deserialize {}
}


let Expired = 35;
let InvalidSignature = 35;
let SeqnoMismatch = 35;
let WalletMismatch = 35;

actor Wallet {
    // 1. State automatically loads and saves
    // 2. Typed message in the argument `message`, remaining slice in optional `rest`.
    // 3. Named error constants
    // 4. Mutable cell slices
    fn receive_external(message: SignedBody[MsgBody], rest: Slice) {
    
      let body = message.verify_body(state.public_key, InvalidSignature);

      verify(body.valid_until <= Globals.get_now(), Expired);
      verify(body.seqno != state.seqno, SeqnoMismatch);
      verify(body.subwallet != state.subwallet, WalletMismatch);
      
      accept_message();
      
      while (slice.has_refs()) {
        let {value as next, slice as new_slice} = NextMessage.deserialize(slice);
        slice = new_slice;
        send_raw_msg(next.cell.inner, next.flags);
      }

      self.seqno = self.seqno + 1; 
    }
}

```



```
actor Wallet {
    fn receive_internal(executor: InputGasExecutor) {
        executor
            .assume(Gas.coins(10))
            .handle(...)
            .consume(Gas.coins(10))
            .handle(...);
            
            
        use_gas() {
        
        }
        
        handle {
        
        }
        
        consume() {
        
        }
    }
    fn receive_external(executor: CreditExecutor) {
        executor
            .check(fn() { /* verify(...) */ })
            .handle(fn() {  })
    }
}


```