Skip to content

Commit 4758f93

Browse files
committed
towards transfer interface implementation
1 parent b333fbc commit 4758f93

File tree

2 files changed

+93
-2
lines changed

2 files changed

+93
-2
lines changed

daml/splice-amulet/daml/Splice/AmuletRules.daml

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import DA.Time
2323
import Splice.Api.FeaturedAppRightV1 (AppRewardBeneficiary(..))
2424
import Splice.Api.Token.MetadataV1 as Api.Token.MetadataV1
2525
import Splice.Api.Token.HoldingV1 qualified as Api.Token.HoldingV1
26+
import Splice.Api.Token.TransferInstructionV1 qualified as Api.Token.TransferInstructionV1
2627
import Splice.Api.Token.TransferPreapprovalV1 qualified as Api.Token.TransferPreapprovalV1
2728
import Splice.Amulet
2829
import Splice.Amulet.TokenApiUtils
@@ -1477,6 +1478,16 @@ template TransferPreapproval
14771478
transferPreapproval_withdrawImpl _self _arg = error "implement"
14781479
transferPreapproval_rejectImpl _self _arg = error "implement"
14791480

1481+
interface instance Api.Token.TransferInstructionV1.TransferFactory for TransferPreapproval where
1482+
view = Api.Token.TransferInstructionV1.TransferFactoryView with
1483+
admin = dso
1484+
meta = emptyMetadata
1485+
1486+
transferFactory_transferImpl _self _arg = error "implement"
1487+
transferFactory_publicFetchImpl _self arg = do
1488+
requireExpectedAdminMatch arg.expectedAdmin dso
1489+
pure (view $ toInterface @Api.Token.TransferInstructionV1.TransferFactory this)
1490+
14801491

14811492
nonconsuming choice TransferPreapproval_Fetch : TransferPreapproval
14821493
with
@@ -1662,3 +1673,85 @@ unfeaturedPaymentContextFromChoiceContext dso choiceContext = do
16621673
pure PaymentTransferContext with
16631674
amuletRules
16641675
context = context with featuredAppRight = None
1676+
1677+
1678+
-- Token standard admin checks
1679+
------------------------------
1680+
1681+
-- FIXME: push to utils
1682+
requireExpectedAdminMatch : Party -> Party -> Update ()
1683+
requireExpectedAdminMatch expected actual = require ("Expected admin " <> show expected <> " matches actual admin " <> show actual) (expected == actual)
1684+
1685+
1686+
-- Transfer
1687+
-----------
1688+
1689+
-- FIXME: adjust sectioning and sharing with external party amulet rules
1690+
1691+
tokenStdTransfer
1692+
: Party
1693+
-> Api.Token.TransferInstructionV1.Transfer
1694+
-> Api.Token.MetadataV1.ExtraArgs
1695+
-> Update Api.Token.TransferInstructionV1.TransferInstructionResult
1696+
tokenStdTransfer dso transfer extraArgs = do
1697+
-- == validate each field of the transfer specification ==
1698+
-- sender: nothing to validate
1699+
-- receiver: validate preapproval if given
1700+
optPreapprovalCid <- lookupFromContextU @(ContractId TransferPreapproval) extraArgs.context transferPreapprovalContextKey
1701+
forA_ optPreapprovalCid \preapprovalCid ->
1702+
fetchChecked (ForOwner with dso; owner = transfer.receiver) preapprovalCid
1703+
-- instrumentId:
1704+
let expectedInstrumentId = amuletInstrumentId dso
1705+
require
1706+
("Expected instrumentId " <> show expectedInstrumentId <> " matches actual instrumentId " <> show transfer.instrumentId)
1707+
(expectedInstrumentId == transfer.instrumentId)
1708+
-- amount:
1709+
require "Amount must be positive" (transfer.amount > 0.0)
1710+
-- requestedAt:
1711+
assertDeadlineExceeded "Transfer.requestedAt" transfer.requestedAt
1712+
-- executeBefore:
1713+
assertWithinDeadline "Transfer.executeBefore" transfer.executeBefore
1714+
-- inputHoldingCids: note that their detailed validation is done in the transfer itself
1715+
require "At least one holding must be provided" (not $ null transfer.inputHoldingCids)
1716+
1717+
-- use a payment context with featuring so the preapproval provider can be featured
1718+
paymentContext <- paymentFromChoiceContext dso extraArgs.context
1719+
-- execute a direct transfer
1720+
-- inputs <- holdingToTransferInputs (ForOwner with dso; owner = transfer.sender) paymentContext transfer.inputHoldingCids
1721+
-- result <- exercise preapprovalCid TransferPreapproval_Send
1722+
-- with
1723+
-- sender = transfer.sender
1724+
-- context = paymentContext
1725+
-- inputs
1726+
-- amount = transfer.amount
1727+
-- description = reason
1728+
1729+
assertWithinDeadline "TransferPreapproval.expiresAt" expiresAt
1730+
transferResult <- exercisePaymentTransfer dso context Transfer with
1731+
sender
1732+
provider
1733+
inputs
1734+
outputs =
1735+
[ TransferOutput with
1736+
receiver
1737+
receiverFeeRatio = 0.0
1738+
amount = amount
1739+
lock = None
1740+
]
1741+
beneficiaries = None
1742+
-- We don't make this configurable. Rewards should
1743+
-- go to the party hosting the receiver. Allowing the sender
1744+
-- to configure arbitrary beneficiaries doesn't make sense.
1745+
-- If needed, we could extend preapprovals to track beneficiaries later.
1746+
let meta = optionalMetadata reasonMetaKey identity description (fromOptional emptyMetadata transferResult.meta).values
1747+
-- strip metadata to avoid duplicating it needlessly
1748+
let result = transferResult with meta = None
1749+
pure (TransferPreapproval_SendResult result (Some (Metadata meta)))
1750+
1751+
1752+
-- return result
1753+
pure Api.Token.TransferInstructionV1.TransferInstructionResult with
1754+
senderChangeCids = toInterfaceContractId <$> optionalToList result.result.senderChangeAmulet
1755+
output = Api.Token.TransferInstructionV1.TransferInstructionResult_Completed with
1756+
receiverHoldingCids = createdAmuletToHolding <$> result.result.createdAmulets
1757+
meta = copyOnlyBurnMeta result.meta

daml/splice-amulet/daml/Splice/ExternalPartyAmuletRules.daml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -407,5 +407,3 @@ amulet_allocationFactory_allocateImpl externalAmuletRules _self arg = do
407407
output = AllocationInstructionResult_Completed with allocationCid
408408
meta
409409

410-
requireExpectedAdminMatch : Party -> Party -> Update ()
411-
requireExpectedAdminMatch expected actual = require ("Expected admin " <> show expected <> " matches actual admin " <> show actual) (expected == actual)

0 commit comments

Comments
 (0)