Auditoria
O que sai e o que entra
Kit/Sources/EscaliburChains/PlanMovement.swift
O que sai e o que entra num plano, com o ativo pelo mesmo id que a tela usa (`Asset.id`). Cada planejador preenche a partir dos valores que ele mesmo gravou na transação, nunca da intenção: e o que o app confere contra o pedido do dono antes de revisar e de novo antes de assinar.
| 1 | import EscaliburCore |
| 2 | import Foundation |
| 3 | |
| 4 | // O que sai e o que entra num plano, com o ativo pelo mesmo id que a tela usa |
| 5 | // (`Asset.id`). Cada planejador preenche a partir dos valores que ele mesmo gravou na |
| 6 | // transacao, nunca da intencao: e o que o app confere contra o pedido do dono antes de |
| 7 | // revisar e de novo antes de assinar. |
| 8 | |
| 9 | extension PlanReview.Movement { |
| 10 | /// A moeda nativa da rede. |
| 11 | static func native(_ chain: Chain, _ amount: BigUInt) -> Self { |
| 12 | Self(assetID: Asset.native(chain).id, amount: amount) |
| 13 | } |
| 14 | |
| 15 | /// Um token por contrato (EVM, Tron, TON) ou mint (Solana). |
| 16 | /// |
| 17 | /// O id e o do ativo da lista curada com esse contrato. No EVM a lista guarda o |
| 18 | /// endereco com as maiusculas do EIP-55, e a comparacao ignora caixa; nas outras |
| 19 | /// redes o endereco e sensivel a caixa e a comparacao e exata. Fora da lista, o id |
| 20 | /// e rede e contrato como vieram: so casa com uma moeda custom que o dono salvou com |
| 21 | /// esse mesmo contrato (o `Asset.id` dela tem a mesma forma); qualquer outro token |
| 22 | /// a conferencia do app recusa. |
| 23 | static func token(_ chain: Chain, contract: String, _ amount: BigUInt) -> Self { |
| 24 | token(chain, amount, fallback: contract) { listed in |
| 25 | chain.family == .evm ? listed.lowercased() == contract.lowercased() : listed == contract |
| 26 | } |
| 27 | } |
| 28 | |
| 29 | /// Um token da lista reconhecido por uma regra propria da rede (na TON, o mesmo |
| 30 | /// mestre do jetton escrito em outra forma de endereco). |
| 31 | static func token(_ chain: Chain, _ amount: BigUInt, fallback: String, matching: (String) -> Bool) -> Self { |
| 32 | let listed = TokenRegistry.tokens.first { asset in |
| 33 | guard asset.chainID == chain.id, case .token(let contract) = asset.kind else { return false } |
| 34 | return matching(contract) |
| 35 | } |
| 36 | return Self(assetID: listed?.id ?? "\(chain.id):\(fallback)", amount: amount) |
| 37 | } |
| 38 | |
| 39 | /// XRP Ledger e Stellar: codigo mais emissor, como `Asset.id` escreve. |
| 40 | static func issued(_ chain: Chain, code: String, issuer: String, _ amount: BigUInt) -> Self { |
| 41 | let listed = TokenRegistry.tokens.first { asset in |
| 42 | guard asset.chainID == chain.id, case .issued(let listedCode, let listedIssuer) = asset.kind else { return false } |
| 43 | return listedIssuer == issuer && listedCode.uppercased() == code.uppercased() |
| 44 | } |
| 45 | return Self(assetID: listed?.id ?? "\(chain.id):\(code):\(issuer)", amount: amount) |
| 46 | } |
| 47 | } |
| 48 | |
| 49 | extension Asset { |
| 50 | /// O ativo da lista (ou a moeda nativa) com este id. So para texto de revisao |
| 51 | /// derivado de um movimento ja validado. |
| 52 | static func listed(id: String) -> Asset? { |
| 53 | for chain in Chain.all { |
| 54 | if let asset = TokenRegistry.assets(on: chain).first(where: { $0.id == id }) { return asset } |
| 55 | } |
| 56 | return nil |
| 57 | } |
| 58 | } |