gpt4 book ai didi

kotlin - 发行人赎回另一方持有的可替代代币

转载 作者:行者123 更新时间:2023-12-02 13:35:52 27 4
gpt4 key购买 nike

我一直在尝试实现一些逻辑来赎回可替代 token ,我的场景如下:

我有一个发行方甲发行可替代的代币,这些将由乙方持有。我需要实现一个场景,甲方将赎回乙方持有的代币。

我的流程是这样的:

  • 甲方 -> 发行持有的代币 -> 乙方
  • 甲方 -> 需要赎回 -> 乙方持有的代币
  • 甲方 -> 向乙方
  • 索取所有类型 X 的代币
  • 甲方<-从<-乙方
  • 接收typeX的 token
  • 甲方 - 兑换从乙方收到的代币
  • 甲方 -> **向 -> 乙方
  • 发送代表 typeY 的新可替代 token

    **typeY的可替代代币数量应与兑换的typeX代币数量相同。

    我知道自然的行为是要求 B 赎回其代币,但由于一些商业案例,我需要在发行方(甲方)这样做

    我试图通过在甲方(又名发行人)中发起交易来实现这一点,我提出以下建议:
    addMoveFungibleTokens() //Move tokens own by Party B back to the issuer Party A
    addFungibleTokensToRedeem() //Party A redeems the tokens that were received from the Party B

    似乎每当我执行
    addMoveFungibleTokens(transactionBuilder, serviceHub, amountToRedeem, PartyB, PartyA)

    我收到以下异常:
    java.lang.IllegalStateException: Insufficient spendable states identified for 50 TokenPointer(class com.template.states.TypeX, e4842e04-5ff2-4eb8-936e-ea3fee82c2fd).

    有没有人知道如何实现我假装的行为?
    我确信 B 方有 50 个 token ,此命令将 token 返回给我:
    run vaultQuery contractStateType: com.r3.corda.lib.tokens.contracts.states.FungibleToken

    似乎由于某种原因 addMoveFungibleTokens() 正试图将 token 从甲方(发行人)转移到乙方

    ## 更新 1 - 试图澄清问题 ##

    假场景:

    PartyA acts central bank and emits money for PartyB. PartyA and B share a group of states which allows them to track how much money was issued. Besides this, whenever new money is emited, PartA also issues a token with the amount of money issued, this money is held by partyB (I am representing money as a fungible token here). For some reason CountryX where PartyA and B operate is changing currency, due > to this the transactions in the old currency need to be converted into a newCurrency. Initially Party A has two currency types oldCurrency and one newCurrency Since oldCurrency is disappearing all the previous transaction have to be converted to new currency.



    甲方(发行人):
    @InitiatingFlow()
    @StartableByRPC
    class PartyAAskTokens(val oldCurrency: String, val newCurrency: String, val partyB: Party): FlowLogic<SignedTransaction>() {

    @Suspendable
    override fun call(): SignedTransaction {
    val counterPartySession = initiateFlow(partyB)

    // Get the type that represents old currency - This can be improved with QueryCriterias
    val oldCurrencyTypeStateRef = serviceHub.vaultService.queryBy<CurrencyType>().states.filter { stateAndRef -> stateAndRef.state.data.currency == oldCurrency }.single()
    val oldCurrencyTypePointer = oldCurrencyTypeStateRef.state.data.toPointer<CurrencyType>()

    // Get the type that represents new currency - This can be improved with QueryCriterias
    val newCurrencyTypeStateRef = serviceHub.vaultService.queryBy<CurrencyType>().states.filter { stateAndRef -> stateAndRef.state.data.currency == newCurrency }.single()
    val newCurrencyTypePointer = newCurrencyTypeStateRef.state.data.toPointer<CurrencyType>()

    // Get state of the user
    // This state allows to keep track on the quantity of tokens issued at a given time
    // For each puchase I am creating a new state (e.g. Date of the operation matters for historical reasons)
    val userOperationState = serviceHub.vaultService.queryBy<UserOperationState>().states

    // Keys of each one of the participants in the transaction
    val ownSignerKey = ourIdentity.owningKey
    val otherPartyKey = partyB.owningKey

    // Propose a currency conversion transaction
    val transactionBuilder = TransactionBuilder(serviceHub.networkMapCache.notaryIdentities.first())

    // Command identifies that this transaction is an exchange of tokens from an old type into a new type.
    val exchangeOldCurrencyForNewCommand = Command(UserOperationContract.Commands.exchangeOldCurrencyForNew(), listOf(ownSignerKey, otherPartyKey))
    transactionBuilder.addCommand(exchangeOldCurrencyForNewCommand)

    // Hold the amount that needs to redeem from the old currency
    var amountToRedeemFromOldCurrencyType:Long = 0

    // Propose new states for the state current state
    userOperationState.forEach { userOperation ->
    run {
    transactionBuilder.addInputState(userOperation)
    transactionBuilder.addOutputState(userOperation.state.data.copy(currency = newCurrency))

    // Generate a new token with new currency, this should match the units of the new state
    val amountOfToken: Amount<TokenType> = userOperation.state.data.amountOfCurrency of newCurrencyTypePointer
    val issueToken: Amount<IssuedTokenType> = amountOfToken issuedBy ourIdentity
    val fungibleToken: FungibleToken = issueToken heldBy counterPartySession.counterparty
    addIssueTokens(transactionBuilder, listOf(fungibleToken))

    // Keep track of the untis that need to be deleted
    amountToRedeemFromOldCurrencyType += userOperation.state.data.amountOfCurrency
    }
    }

    // Generate the amount to redeem
    val redeemQuantity = amountToRedeemFromOldCurrencyType of oldCurrencyTypePointer

    // Notify PartyB that you are requiring this amount of token
    counterPartySession.send(AmountRedeemRequest(redeemQuantity))

    // Get the token from CounterParty (PartyB)
    val fungibleTokenToRedeemStateRef = subFlow(ReceiveStateAndRefFlow<FungibleToken>(counterPartySession))
    //val fungibleTokens = counterPartySession.receive<List<FungibleToken>>().unwrap { it }

    // TODO: How to improve this code if there is an exception here I will loose all my old tokens that need to be redeemed.
    // ############## EXCEPTION_HERE ##############

    // Redeem the token in transaction
    addTokensToRedeem(transactionBuilder, fungibleTokenToRedeemStateRef)

    // Sign the transaction using the your own key
    val iSignedTransaction = serviceHub.signInitialTransaction(transactionBuilder)

    // Ask others participants to sign
    val signedTransaction = subFlow(CollectSignaturesFlow(iSignedTransaction, listOf(counterPartySession)))
    return subFlow(FinalityFlow(signedTransaction, listOf(counterPartySession)))
    }
    }

    乙方(持有人):
    @InitiatedBy(PartyAAskTokens::class)
    class PartyBGiveTokenBack(val counterPartySession: FlowSession): FlowLogic<SignedTransaction>() {
    @Suspendable
    override fun call(): SignedTransaction {

    val tokenAmountToRedeem = counterPartySession.receive<AmountRedeemRequest>().unwrap { it }
    val (inputs, outputs) = TokenSelection(serviceHub).generateMove(
    lockId = runId.uuid,
    partyAndAmounts = listOf(PartyAndAmount(counterPartySession.counterparty, tokenAmountToRedeem.amountOfTokenToSendBack)),
    changeHolder = ourIdentity
    )

    // Send the token states.
    subFlow(SendStateAndRefFlow(counterPartySession, inputs))

    // Send the tokens
    // Not needed because through the state I can get to the data.
    //counterPartySession.send(outputs)

    // validate data
    val stx = subFlow(object: SignTransactionFlow(counterPartySession) {
    override fun checkTransaction(stx: SignedTransaction) {
    // TODO: Check quantity of tokens to be redeemed is the same as the tokens to be issued
    // TODO: Check if the states point to new token type.
    }
    })

    return subFlow(ReceiveFinalityFlow(counterPartySession, stx.id))
    }
    }

    即使知道在这种情况下乙方是持有
    代币,在这种情况下甲方需要从
    一种货币对另一种货币。由于该提案,各州
    "userOperationState"需要转换成 newCurrency,也
    newCurrency 类型的新 token 来替换 oldCurrency 的旧 token
    需要生成(参见 PartyA 的代码)。最后是旧的
    乙方拥有的代币需要甲方赎回(只有甲方可以
    这样做与原始问题上的业务逻辑有关):
    实现这一点,我正在移动 oldCurrencyType 的所有 token ,仍然
    存在于甲方(持有人)到甲方(发行人),我正在赎回它们。

    我正在使用 SendStateAndRefFlow 和 ReceiveStateAndRefFlow ,它似乎正在工作。如果收到来自 PartyB 的 token StateRef 后出现异常(在 PartyA 代码上查找这个##############
    EXCEPTION_HERE ##############),PartyB 似乎保留了旧 token 。

    我在 Slack channel 中被告知流不是原子的,事务是原子的,并且 subFlow() 的执行将创建一个新事务。
    基于此,我期望 subFlow() 会进行更改,并且如果在它之后抛出异常,则只会保留其更改,但这不是它发生的情况,似乎事务在subFlow() 也被回滚。有人可以澄清这一点,或者指出一些关于子流的好文档吗?

    关于第一个问题:
    我无法在我的代码中使用此函数 addFungibleTokensToRedeem() 而不将 token 移回。原因是甲方是代币的发行者。由于我使用的是可替代代币,因此当它们被发行时,它们已经被派对 B 持有,因此,
    我的保险库没有 token 。前面提到的方法调用了这行代码:
     val fungibleStates = tokenSelection.attemptSpend(amount, transactionBuilder.lockId, queryCriteria)

    并且似乎在引擎盖下这个方法正在访问没有 token 的 PartyA 保险库......

    最佳答案

    在我看来,您所描述的几乎与 token SDK 中当前存在的内容相同。与其编写一个全新的流程,不如将现有的赎回代币流程与以发行者指定应该赎回哪些代币开始的附加流程包装起来?我想你可能只需要几行额外的代码就可以做到这一点。

    关于您为什么会遇到异常,除非我看到代码,否则我不知道。我建议你重新开始包装 RedeemFungibleTokensFlowRedeemTokensFlowHandler处理与发行人而不是赎回方开始赎回过程的流程。

    关于kotlin - 发行人赎回另一方持有的可替代代币,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57323633/

    27 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com