# From Contracts to Map

**This feature will be implemented in the next Rhône upgrade.**

Map simplifies smart contract code for accessing and storing data. [ALPH.bet](https://alph.bet) utilizes this feature to manage data like player and round information more efficiently. This article will explain the changes made to adapt the smart contract to use [Mapping](https://docs.alephium.org/ralph/getting-started#map-rhone-upgrade-only).

> Read our articles about the dapp we developed: [part 1](https://blog.notrustverify.ch/1-alephiums-prediction-game), [part 2](https://blog.notrustverify.ch/2-prediction-game-on-alephium), and [part 3](https://blog.notrustverify.ch/3-prediction-game-on-alephium).

### Overview of Changes

Each time someone places a bet, a contract is deployed with details like the bet amount and specifics. Several functions utilize subcontracts to check if someone has already bet in a round or to withdraw the bet once it's completed.

#### Previous Implementation Without Mapping

*The following code demonstrates how these functions were handled without Mapping:*

**Checking if someone already played:**

```rust
assert!(!contractExists!(subContractId!(bidderContractId)), ErrorCodes.AlreadyPlayed)
```

[Source](https://github.com/notrustverify/predictalph-contracts/blob/0c10c244cd7aec365e5917298e3d9ac9d54bffb7/contracts/multiple-choice/predict.ral#L143)

**Deploying a smart contract when someone bets:**

```rust
let selfContractId = selfContractId!()
let (encodedImmFields, encodedMutFields) = PunterChoice.encodeFields!(selfContractId, caller, epoch, side, bidAmount, claimedByAnyoneTimestamp)
let _ = copyCreateSubContract!{caller -> ALPH: 1 alph}(bidderContractId, punterTemplateId, encodedImmFields, encodedMutFields)
```

[Source](https://github.com/notrustverify/predictalph-contracts/blob/0c10c244cd7aec365e5917298e3d9ac9d54bffb7/contracts/multiple-choice/predict.ral#L154-L156)

**Withdrawing:**

```rust
let betInfoContractId = subContractId!(SubContractTypes.PunterChoice ++ toByteVec!(addressToClaim) ++ epochNumber)
let roundContractId = subContractId!(SubContractTypes.RoundMultipleChoice ++ epochNumber) 
assert!(contractExists!(roundContractId), ErrorCodes.RoundNotExists)
assert!(contractExists!(betInfoContractId), ErrorCodes.PunterChoiceNotExists)

if (contractExists!(roundContractId) && contractExists!(betInfoContractId)){
    let betInfoCaller = getBetInfoByEpoch(addressToClaim, epochNumber)
            
    let addressPunterChoice = betInfoCaller.getAddress()
    let canBeClaimedAt = betInfoCaller.getClaimedByAnyone()
            
    if(addressToClaim != from){
       assert!(timestampNow > canBeClaimedAt, ErrorCodes.CannotBeClaimedYet)
    }

    let amountPunterChoice = betInfoCaller.getAmountBid()
    let upBid = betInfoCaller.getBid()

    let round = getRoundByEpochByteVec(epochNumber) 
    round.userClaimRewards(addressToClaim, amountPunterChoice, upBid)
    betInfoCaller.destroy(from)
}
```

[Source](https://github.com/notrustverify/predictalph-contracts/blob/0c10c244cd7aec365e5917298e3d9ac9d54bffb7/contracts/multiple-choice/predict.ral#L179-L197)

Managing subcontracts can become complex with numerous contracts, which is where mapping becomes useful. This feature reduces complexity and provides a good abstraction.

> Key-value pairs are fundamental in computing, linking an identifier (key) to a piece of data (value). For example, the key might be CITY, and the value might be BERLIN. Mapping is a set of key-value pairs.
> 
> [Alephium on Twitter](https://twitter.com/alephium/status/1778800481940459707)

### New Implementation with Mapping

For ALPH.bet, the major change was replacing contract management of players with a simple struct:

```rust
struct PunterChoice {
   predictionContractId: ByteVec,
   punterAddress: Address,
   epoch: U256,
   side: U256,
   amountBid: U256,
   claimedByAnyoneAt: U256
}
```

And adding this map at the beginning of the contract:

```rust
mapping[ByteVec, PunterChoice] punters
```

This simplifies checking if someone has already played:

```rust
assert!(!punters.contains!(bidderKey), ErrorCodes.AlreadyPlayed)
```

Previously, accessing player information involved computing the path and checking for subcontract existence:

```rust
fn getBetInfoByEpoch(from: Address, epochToGet: ByteVec) -> PunterChoice {
   let bidderContractId = subContractId!(SubContractTypes.PunterChoice ++ toByteVec!(from) ++ epochToGet)
   assert!(contractExists!(bidderContractId), ErrorCodes.PunterChoiceNotExists)
    
   return PunterChoice(bidderContractId)
}
```

This has been replaced by one line, with the subcontract ID becoming the map key:

```rust
let betInfoContractKey = SubContractTypes.PunterChoice ++ toByteVec!(addressToClaim) ++ epochNumber
let betInfoCaller = punters[betInfoContractKey]
```

So when the refactor is done, the withdrawing function will look like this. The example below demonstrate how easy it is to access to player information and delete (=get back locked ALPH) the entry.

```rust
let roundContractId = subContractId!(SubContractTypes.RoundMultipleChoice ++ epochNumber)
let betInfoContractKey = SubContractTypes.PunterChoice ++ toByteVec!(addressToClaim) ++ epochNumber
assert!(contractExists!(roundContractId), ErrorCodes.RoundNotExists)
assert!(punters.contains!(betInfoContractKey), ErrorCodes.PunterChoiceNotExists)

if (contractExists!(roundContractId) && contractExists!(betInfoContractKey)){
   let betInfoCaller = punters[betInfoContractKey]         
   let addressPunterChoice = betInfoCaller.punterAddress
   let canBeClaimedAt = betInfoCaller.claimedByAnyoneAt
   
   if(addressToClaim != from){
      assert!(timestampNow > canBeClaimedAt, ErrorCodes.CannotBeClaimedYet)
   }
   
   let amountPunterChoice = betInfoCaller.amountBid
   let upBid = betInfoCaller.side

   let round = getRoundByEpochByteVec(epochNumber)

   round.userClaimRewards(addressToClaim, amountPunterChoice, upBid)
   punters.remove!(from, betInfoContractKey)
}
```

### Conclusion

This new feature significantly aids in writing cleaner and more optimized code. The abstraction enhances the developer experience by simplifying the logic behind managing and deploying subcontracts.

Although the smart contract isn't much shorter, it is cleaner and greatly reduces the complexity of using subcontracts with Ralph.

---

%%[footer-english] 

---

This version maintains the technical detail while improving readability and emphasizing the benefits of the changes.
