Using Cadence and MultiSign to achieve Flowns contract management authority segmentation

https%3A%2F%2Ftrello.com%2F1%2Fcards%2F6

![](https://ift.tt/RvE7TLM)

# Use Cadence plus MultiSign to realize the split of Flowns contract management authority

In the previous article [Detailed explanation of Flow transaction process and structure](https://ift.tt/OL4TJQi), we learned about Flow’s Cadence and transaction process, transaction data structure, and also learned about the classic usage scenarios of multi-signature — – Payment of handling fee.

In fact, the flexibility of Flow transaction signature is not only reflected in the payment of transaction fees, but we can extend this idea to more complex permissions and scenarios.

The multi-signature feature can support more flexible Cadence scripts, provide the basis for writing complex Cadence permissions and logic, and open the permission restrictions for script execution at the architectural level, which can not only complete permission combination, but also split permissions through this mechanism.

Below we describe the advantages and practices of multi-signature in combination with actual scenarios.

## Multi-signature scene

According to the logic of fee payment, multi-signature is actually the same implementation idea. The transaction body is transmitted, and different authorizers assemble their signatures into `payloadSignatures`, and finally hand over to the payer to encapsulate the signature and send it to the chain.

Such patterns and processes can be used in actual production environments.

For example, the private key of the current Flowns contract deployment account has the authority to create and manage domain names under the entire Flowns root domain name, which is the so-called super administrator.

One of the features of Flowns is that it supports multiple root domain names other than `fn`. However, because the authority management of multiple root domain names is complicated and the needs of future root domain name partners are uncertain, so much is reserved in the contract writing stage. Based on the price setting and deposit management interface for Vault resources. However, the function of simultaneously supporting multiple root domain name managers to isolate each other’s authority has not been implemented.

Although the management authority of the contract is concentrated on a private key, we can still complete the split and authorization of the root domain name authority through Cadence and multi-signature.

## Flowns && Lilico root domain name casting authority authorization

As a wallet service provider, [Lilico](https://lilico.app/) needs to issue its own root domain name, and use [Flowns](https://flowns.org) domain name resources to support the ability to nest NFT & FT , let the Flowns domain name become the asset container of Lilico users, which can greatly improve the user experience of users when using wallets to transfer money to third parties. An issue where users of uninitialized Vault and Collection resources could not receive assets will be resolved.

But to achieve such a function, the super administrator of Flowns needs to authorize the Lilico service and safely help Lilico to complete the creation and distribution of domain names under the root domain name.

To implement this function safely, Flowns and Lilico need to work together to solve the following problems:

– Security Question

– How to delegate the authority of the new root domain name to Lilico or other third parties without affecting the main business of the existing root domain name `fn` of Flowns

– How to confirm transaction permissions to prevent man-in-the-middle attacks, or tamper with transaction content, resulting in the theft of Flowns core permissions

– If there is a second root domain partner in the future, how to isolate their authority from the existing partners so as not to affect each other

– experience problems

– How to solve the problem that users can have initialized resources when there is insufficient transaction fee or insufficient Flow

– How to ensure that requests for multiple authorized transactions will not block or even fail in the case of high concurrency

Next, we try to solve the above-mentioned problems in a way that can support the transaction characteristics of Cadence and Flow, based on a multi-party service architecture and taking into account the openness and security.

### Security Question

**Administrator private key permission split and isolation**

It does not affect the existing root domain name authority of Flowns and isolates it from external authority. We isolate it through the script whitelist performed by the Flowns server. That is to say, the Flowns backend service is responsible for signing transactions and verifying Cadence scripts.
Only third-party accounts are allowed to execute specific scripts. In the multi-signature process, when the Flowns administrator signs, the script content will be compared and verified to ensure that the transaction executor and the authorizer match the permissions of the script before signing. Authorized minting transactions for root domains.

That is to say, Flowns can provide the authorized script to the third party that needs to be called through the interface, and then check the multi-signature link to check whether the script in the transaction body is authorized to be called externally. Only certain scripts can be executed,

Because the invocation of the root domain name in Flowns is reflected in the parameter form of RootDomainId in the script, for the release script of Lilico’s new root domain name, Flowns only needs to provide a script that can accept and issue the parameters based on the root domain name, and other parameters All will be hardcoded in the Cadence script, as part of the script verification.

After receiving the authorization request from Lilico, Flowns will first verify whether the address of the authorizers in the script transaction body matches the whitelist, and if it matches, the authorization operation will be performed.

The advantage of this is that if the script of the transaction matches and the authorizer matches, there is no problem with determining the authority owner. Even if an intermediary tampered with any field in the transaction body and deceived Flowns’ verification, it still needs to pass the Flow network. Permission verification, so the overall solution is safe and lightweight and easy to implement.

**Permission Grant and Confirmation**

As mentioned above, the Flowns server will establish an association relationship with the authorization script according to the address of the third party, verify the script’s authority through Cadence’s hash, and verify the requester’s authority with the payload information in the transaction body, so that the server has isolation. the ability of permissions.
Let’s look at the Js code

“`javascript

// Authorization whitelist configuration
export const whitelist = {
testnet: {
‘0x**********77cd’: [‘mintLilicoDomain’],
},
mainnet: {},
}

// Authorization script definition
const scripts = {
mintLilicoDomain: () => {
const script = `Lilico mint script that only allow mint lilico root domain` // The script here is to allow only the root domain name of lilico to cast flowns domain name
return script
},
// or other transaction scripts that require authorization in the future
otherScripts:() => {
}
}

export const getScripts = (key) => {
const scriptFunc = scripts[key]
const script = scriptFunc ? scriptFunc() : ”
return script
}

// script validation
export const verifyTrx = (script, address) => {

let whiteList = whitelist[network]
let scriptList = whiteList[address]
if (scriptList.len == 0) return false
let scriptHash = sha3(script)

var flag = false
scriptList.forEach((key) => {
let script = getScripts(key)
let hashStr = sha3(script)
if (scriptHash === hashStr) {
flag = true
}
})
return flag
}

“`

Here, only simple configuration and verification are needed to ensure security, and the authorized script can be called by a third party.

> Receive Raw transaction and assemble with manual signature processing

“`javascript
import * as fcl from ‘@onflow/fcl’

// receive post request
const data = req.body

const { transaction } = data

// init fcl config
fclinit()

const {
script,
payerAddress,
referenceBlockId,
proposalKey,
gasLimit,
authorizers,
payloadSignatures,
} = transaction

// Verify that the script is authorized
let verified = verifyTrx(script, payerAddress)

if (verified) {
// Manually assemble the transaction body
let trxMsg = {
script: script,
refBlock: referenceBlockId,
arguments: transaction.arguments,
proposalKey: {
address: proposalKey.address,
keyId: proposalKey.keyIndex,
sequenceNum: proposalKey.sequenceNumber,
},
payer: payerAddress,
authorizers,
payloadSigs: payloadSignatures,
gasLimit: gasLimit,
}
// RLP encode encodes the transaction body
let msg = fcl.encodeTransactionPayload(trxMsg)
// Sign the encoded msg for a visible reference
let signature = sign(msg)

// Assemble the signed data into the payloadSignatures of the original transaction and return
transaction.payloadSignatures = transaction.payloadSignatures.concat({
address: flownsAddr,
keyIndex: 0,
signature,
})

// Return the signed transaction data, send it to the third party for final signature and send
return res.json(transaction)

“`

The code here does several things:

– Accept transaction parameters from external third parties by listening to post requests

– Destructuring transaction parameters

– Verify the authorization address and the corresponding script permissions

– Assemble raw transaction data supported by fcl

– RLP encode transaction data (payload) to generate message

– Use the local private key to call the local signature function to sign the message

– Assemble the signature information into the payloadSignatures array of the original transaction data

– returns the signed result

The rest of the process is handed over to a third-party service for the final package signature and sent to the Flow blockchain

**Multi-root domain name authority isolation management**

Let’s look at the script first:

“`javascript

import Domains from ${flownsAddr} // The address will be replaced according to the unreachable network to make the test network and the main network common script
import Flowns from ${flownsAddr}
import NonFungibleToken from ${flowNonFungibleAddr}
import FungibleToken from ${flowFungibleAddr}

// The parameter only holds the domain name
transaction(name: String) {
let client: &{Flowns.AdminPrivate}
let receiver: Capability
// Three-party authorization is used here, user, lilico and Flowns
prepare(user: AuthAccount, lilico: AuthAccount, flowns: AuthAccount) {
let userAcc = getAccount(user.address)
// check user balance
// Prevent users from being unable to initialize the domain name collection resource due to insufficient balance
let userBalRef = userAcc.getCapability(/public/flowTokenBalance).borrow()
if userBalRef!.balance (from: /storage/flowTokenVault)
let userReceiverRef = userAcc.getCapability(/public/flowTokenReceiver).borrow()
userReceiverRef!.deposit(from: (Domains.CollectionPublicPath).check() == false {
if user.borrow(from: Domains.CollectionStoragePath) != nil {
user.unlink(Domains.CollectionPublicPath)
user.link(Domains.CollectionPublicPath, target: Domains.CollectionStoragePath)
} else {
user.save((Domains.CollectionPublicPath, target: Domains.CollectionStoragePath)
}
}

self.receiver = userAcc.getCapability(Domains.CollectionPublicPath)
self.client = flowns.borrow(from: Flowns.FlownsAdminStoragePath) ?? panic(“Could not borrow admin client”)
}
execute {
self.client.mintDomain(domainId: 2, name: name, duration: 3153600000.00, receiver: self.receiver) // Here the root domain name id and lease duration are hardcoded
}
}

“`

The above code is a bit complicated. In a nutshell, it is a script that defines a mint domain name of the administrator, and is executed through three-party multi-signature authorization. We can only focus on the commented part:

– Transaction parameters: only the domain name parameter is reserved, which simplifies third-party calls and operations

– Authorization parameter (prepare): Three signatures are used here. This transaction requires three signatures to execute. We will also see in the transaction body that there are three addresses in the authorizers, and the payloadSignatures also requires three signatures. Elements

– User – the initiator of the transaction, that is, the user who applies for the Lilico root domain name (proposer)

– Lilico – the verification and authorizer of the transaction, the payer of the transaction fee

– Flowns —— Foundry authority authorizer (Flowns admin)

– In addition, two judgments were made in the script

– Determine whether the user’s Flow balance is enough to initialize Flowns Collection resources, if not, subsidize it through Flowns’ account

– Determine whether the user has initialized the Flowns Collection, and if not, help the user to initialize the Collection

– In the execution code block, the authority of the management authority mintDomain is separated by hard-coded parameters. The script only allows to call the root domain name with RootDomainId of 2, that is to say, only the Flowns domain name can be issued through the root domain name of Lilico, which is natural to isolate the authority of other root domain names.

**How ​​to solve the problem that users can have initialized resources when they have insufficient transaction fees or insufficient Flow**

In fact, in the comments of the previous script, it is not difficult to find that the Cadence script has been processed for different situations of users, helping users to make up for expenses and initialize in advance without resources. This ensures that the script can be executed successfully under various conditions.

That’s what makes Cadence fascinating.

**How ​​to deal with high concurrency**
Let’s look at the transaction body

“`json
{
script: ‘Cadence script …’, // Cadence transaction script
refBlock: ‘d719c892c80b45de3d19c459dc7eeba8ab809b5f3b007a51c69f697b7eb42361’, // referenced block ID
arguments: [ { type: ‘String’, value: ‘Test’ } ], // Arguments for the Cadence transaction
proposalKey: { address: ‘0xe242ccfb4b8ea3e2’, keyId: 0, sequenceNum: 480 }, // transaction initiator information
payer: ‘0xc6de0d94160377cd’, // transaction fee payer information
authorizers: [ ‘0xe242ccfb4b8ea3e2’, ‘0xc6de0d94160377cd’, ‘0xb05b2abb42335e88’ ],
gasLimit: 1000,
payloadSignatures: [
{
address: ‘0xe242ccfb4b8ea3e2’,
keyIndex: 0,
signature: ‘9aa7ca757c0c995d1cc11b71c6c5d3b83be92708905c8ba4528fadc602438acd027b479e1546f9ed96a3c9f8df424eccd318333c7f55378ce4994b164972c450’
},{…},{…}
],
envelopeSignatures: [
{
“address”: “0x01”,
“keyId”: 1,
“sig”: “0xabc123”
}
]
}

“`

Here `proposalKey` we use the user as the proposer, so that in the case of processing multiple users’ simultaneous requests, the sequenceNum of the transaction authorizer itself will not be blocked or conflicted due to waiting for the confirmation of the transaction block. In theory, proposers can achieve unlimited concurrency, and the throughput capacity of blocks will not be blocked by a single point, which solves the problem of simultaneous requests by multiple users. Lilico and Flowns only need to focus on verification and authorization.

This is also a point that we need to pay attention to when building server-side authorization and multi-signature scenarios. Once high concurrent requests are involved, the best way is to let the request initiator act as a proposer to avoid blocking and some unnecessary transaction monitoring and errors. deal with.

So far, we have seen the flexibility of Cadence script and the realization of permission isolation. Under the flexible authorization and signature mechanism, we can achieve blockchain-level security with simple code.

## specific process

For your convenience, you can combine the above content with the following figure to understand the overall three-party participation authorization process:

![](https://ift.tt/hk3jCRi)

## Precautions

This scheme is not the optimal solution, but a more general authorization and signature scheme can be built based on it.

Then the core of the server is still the management of the private key. Since Flowns uses a third-party servless service, the configuration of the private key needs to be completed using the environment variables of the hosting service. Although account login and 2FA are configured, this is not To be foolproof, it is recommended that the administrator of the core contract periodically change the Key.

Because the design of the Flow account model is relatively abstract, and it also supports multi-signature in the form of key weight, it is an ideal and high-security approach to periodically change the key.

Although the advantage of Cadence lies in flexibility, it also has a certain risk of being attacked and abused. Therefore, when it comes to the core authorization operation, the script verification must be carried out. segmentation and isolation management.

The next article will explain in detail how to implement a simple resource-based centralized authorization and decentralization smart contract logic through contracts.

## At last

This solution is only designed to simplify the contract and satisfy the limited authority granted by the contract administrator to the third-party partner. It is not suitable for all situations. Ideally, the on-chain logic and management method should be used to manage the root domain name.

Due to the features and advantages of Cadence, we can complete flexible permission granting without modifying existing contracts, and complete multi-party signature authorization and verification through the public interface and permission configuration without affecting the security of the entire transaction.

This can be applied to similar scenarios based on smart contract combination in the future, and can also be used as an off-chain transition solution to help some infrastructures complete the docking and collaboration of third-party services.

Of course, the author will continue to explore in the Cadence application layer, try more business types and summarize and optimize the existing models, try to solve complex problems with the best practices, and use Cadence as a new generation of smart contract language features and advantages in the application layers to the max.

This article is reproduced from: https://caos.me/c2787115-98db-467d-8e3b-ea5028799961
This site is for inclusion only, and the copyright belongs to the original author.

Leave a Comment