Skip to content

Latest commit

 

History

History
278 lines (213 loc) · 18.8 KB

恒星开发指南之发送和接受资产.md

File metadata and controls

278 lines (213 loc) · 18.8 KB

恒星入门开发指南

原文链接:https://www.stellar.org/developers/guides
翻译:吴魏杰 校对:

一. 开始恒星之旅

  1. 恒星网络概述
    基于恒星的网络,您可以构建移动钱包,银行工具,为自己付费的智能设备,以及任何您梦寐以求的支付方式。尽管恒星是一个复杂的分布式系统,但是使用它并不需要很复杂。

    大多数应用程序通过Horizon(一种RESTful HTTP API服务器)与Stellar网络进行交互。Horizon使您能够直接提交交易,查看账户和订阅活动。 因为它只是HTTP,所以您可以使用Web浏览器,简单的命令行工具(如cURL)或Stellar SDK(用于您最喜爱的编程语言)与Horizon进行通信。
    安装Horizon的最简单方法是使用恒星/快速启动docker镜像。(https://hub.docker.com/r/stellar/quickstart/)

    Stellar.org维护用于与Horizon进行通信的JavaScript,Java和Go-based SDK。 还有社区维护的Ruby,Python和C#SDK。

    在恒星网络中,每台Horizon服务器都连接到Stellar Core。 恒星核心软件通过恒星共识协议(SCP)为每项交易的状态确认并同意其他核心实例的努力工作。 恒星网络本身是由世界各地的各种个人和实体运行的相连恒星核的集合。 某些实例拥有与您进行通信的Horizon服务器,而其他实例只能用于为整个网络添加可靠性。

    最简单安装Stellar Core的方法是通过恒星/快速启动docker镜像(https://hub.docker.com/r/stellar/quickstart/)

    您可能希望托管您自己的Stellar Core实例,以便在不依赖第三方的情况下提交交易,对谁信任有更多控制权,或仅仅是为了帮助其他人更加可靠和强大。

    恒星网络是由世界各地的不同人员和组织共同维护的恒星内核。 网络的分布式特性使其可靠和安全。

    所有这些恒星核心 - 节点网络 - 最终达成一系列交易。 网络上的每笔交易都需要少量费用:100次(0.00001 XLM)。 这笔费用有助于防止不良行为者发送垃圾邮件。

    为了帮助你测试你的应用或者工具,Stellar.org提供了一个小型的测试网络和Horizon实例。(https://www.stellar.org/developers/guides/concepts/test-net.html)

开始创建一个账号

您需要在Stellar网络上做任第一件事是创建一个帐户。 帐户将您的所有资金存放在Stellar网络中,并允许您发送和接收付款 - 事实上,Stellar中的几乎所有内容都以某种方式与帐户相关联。
每个恒星账户都有公钥和秘密种子。 恒星使用公钥密码术来确保每笔交易都是安全的。 公共密钥始终可以安全共享 - 其他人需要它来识别您的帐户并验证您是否授权了交易。 但是,种子是私人信息,证明您拥有自己的账户。 你不应该与任何人分享种子。 这就像锁的组合 - 任何知道组合的人都可以打开锁。 同样,任何知道您账户种子的人都可以控制您的账户。
如果你熟悉公钥密码学,你可能想知道种子和私钥的区别。 种子实际上是用于为您的帐户生成公钥和私钥的单个秘密数据片段。 为方便起见,恒星的工具使用种子而不是私钥:要完全访问帐户,只需提供种子,而不是公钥和私钥。
由于种子必须保密,因此创建帐户的第一步是创建自己的种子和密钥 - 当您最终创建帐户时,您只会将公钥发送到Stellar服务器。 您可以使用以下命令生成种子和密钥:

     // create a completely new and unique pair of keys
     // see more about KeyPair objects: https://stellar.github.io/js-stellar-sdk/Keypair.html
     var pair = StellarSdk.Keypair.random();
	 pair.secret();
    // SAV76USXIJOBMEQXPANUOQM6F5LIOTLPDIDVRJBFFE2MDJXG24TAPUU7
    pair.publicKey();
    // GCFXHS4GXL6BVUCXBWXGTITROWLVYXQKQLF4YH5O5JT3YZXCYPAFBJZB

既然您拥有种子和公钥,您可以创建一个账户。 为了防止人们制造大量不必要的帐户,每个帐户必须具有1流明的最小余额(流明是恒星网络的内置货币)。 由于您还没有流明,所以您无法为帐户付款。 在现实世界中,您通常会支付一个销售流明的交易所,以创建一个新账户。然而,在Stellar的测试网络上,您可以向我们友好的机器人Friendbot询问一个非常胖的钱包,为您创建一个帐户。
要创建一个测试帐户,请向Friendbot发送您创建的公钥。 它将使用该公钥作为帐户ID创建并资助一个新帐户:
 // The SDK does not have tools for creating test accounts, so you'll have to.
 // make your own HTTP request.
 var request = require('request');
 request.get({
 url: 'https://friendbot.stellar.org',
 qs: { addr: pair.publicKey() },
 json: true
 }, function(error, response, body) {
if (error || response.statusCode !== 200) {
console.error('ERROR!', error || body);
}
else {
console.log('SUCCESS! You have a new account :)\n', body);
}

});
现在是最后一步:获取帐户的详细信息并检查余额。 账户可以携带多种余额 - 每种货币的余额。

var server = new StellarSdk.Server('https://horizon-testnet.stellar.org');
// the JS SDK uses promises for most actions, such as retrieving an account
server.loadAccount(pair.publicKey()).then(function(account) {
console.log('Balances for account: ' + pair.publicKey());
account.balances.forEach(function(balance) {
console.log('Type:', balance.asset_type, ', Balance:', balance.balance);
});
});

发送和接受支付

大多数时候,你会把钱汇给有自己账户的其他人。 但是,对于本交互式指南,您应该使用您用于创建第一个帐户的相同方法进行第二个帐户的交易。

发送支付

行为改变恒星的事情,如发送付款,更改账户或提供交易各种货币的交易称为操作。为了实际执行某项操作,您需要创建一个交易,该交易只是一组伴随一些额外信息的操作,例如帐户正在进行交易以及加密签名以验证交易是否真实。如果交易中的任何操作失败,则全部失败。 例如,假设您有100流明,并且您进行两次60流明的付款操作。 如果您进行两次交易(每次只进行一次操作),第一次交易将成功,第二次交易将失败,因为您没有足够的流明。 你将剩下40流明。 但是,如果您将这两笔款项分组为一笔交易,则两笔款项都将失效,并且您的帐户仍会保留100流明。
最后,每笔交易都需要一小笔费用。 就像帐户的最低余额一样,这笔费用有助于阻止人们通过大量交易来超载系统。 被称为基本费用,它非常小 - 每次操作100次(这是0.00001 XLM;勺子比流明的这种微小部分更容易谈论)。 有两次操作的交易将花费200次。

建立一个交易

恒星存储并以称为XDR的二进制格式传输交易数据。 幸运的是,Stellar SDK提供了处理所有这些的工具。 以下是您可能会发送10流明到另一个帐户的方式:

 var StellarSdk = require('stellar-sdk');
 StellarSdk.Network.useTestNetwork();
 var server = new StellarSdk.Server('https://horizon-testnet.stellar.org');
 var sourceKeys = StellarSdk.Keypair
.fromSecret('SCZANGBA5YHTNYVVV4C3U252E2B6P6F5T3U6MM63WBSBZATAQI3EBTQ4');
var destinationId = 'GA2C5RFPE6GCKMY3US5PAB6UZLKIGSPIUKSLRB6Q723BM2OARMDUYEJ5';
// Transaction will hold a built transaction we can resubmit if the result is unknown.
var transaction;

// First, check to make sure that the destination account exists.
// You could skip this, but if the account does not exist, you will be charged
// the transaction fee when the transaction fails.
server.loadAccount(destinationId)
// If the account is not found, surface a nicer error message for logging.
.catch(StellarSdk.NotFoundError, function (error) {
throw new Error('The destination account does not exist!');
})
// If there was no error, load up-to-date information on your account.
.then(function() {
   return server.loadAccount(sourceKeys.publicKey());
})
.then(function(sourceAccount) {
// Start building the transaction.
transaction = new StellarSdk.TransactionBuilder(sourceAccount)
  .addOperation(StellarSdk.Operation.payment({
    destination: destinationId,
    // Because Stellar allows transaction in many currencies, you must
    // specify the asset type. The special "native" asset represents Lumens.
    asset: StellarSdk.Asset.native(),
    amount: "10"
  }))
  // A memo allows you to add your own metadata to a transaction. It's
  // optional and does not affect how Stellar treats the transaction.
  .addMemo(StellarSdk.Memo.text('Test Transaction'))
  .build();
// Sign the transaction to prove you are actually the person sending it.
transaction.sign(sourceKeys);
// And finally, send it off to Stellar!
return server.submitTransaction(transaction);
})
.then(function(result) {
console.log('Success! Results:', result);
})
.catch(function(error) {
console.error('Something went wrong!', error);
// If the result is unknown (no response body, timeout etc.) we simply resubmit
// already built transaction:
// server.submitTransaction(transaction);
});

让我们一步步分解来看看发生了什么

  1. 通过加载来自Stellar网络的关联帐户数据,确认您发送的帐户ID是否实际存在。 如果你跳过这一步,虽然一切都很好,但这样做会让你有机会避免做出你知道会失败的交易。 您也可以使用此通话执行您可能希望对目标帐户执行的任何其他验证。 例如,如果您正在编写银行业务软件,那么这是插入合规性检查和KYC验证的好地方。

      server.loadAccount(destinationId)
      .then(function(account) { /* validate the account */ })
    
  2. 加载您从中发送的帐户的数据。 一个账户一次只能执行一个交易,并且有一个叫序列号的东西,这有助于Stellar验证交易的顺序。 交易的序列号需要与帐户的序列号匹配,所以您需要从网络获取帐户的当前序列号。

     .then(function() {
     return server.loadAccount(sourceKeys.publicKey());
    })
    

    在构建交易时,SDK会自动增加帐户的序号,因此如果您想执行第二笔交易,则不需要再次检索此信息。

  3. 开始建立交易。 这需要一个账户对象,而不仅仅是一个账户ID,因为它会增加账户的序列号。

     var transaction = new StellarSdk.TransactionBuilder(sourceAccount)
    
  4. 将付款操作添加到帐户。 请注意,您需要指定您要发送的资产的类型 - 恒星的“本币”货币是流明,但您可以发送任何类型的资产或货币(从美元到比特币)到任何您信任发行人的资产 兑换(更多细节见下文)。 但现在,我们将坚持使用流明,这在SDK中被称为“本地”资产:

    .addOperation(StellarSdk.Operation.payment({
     destination: destinationId,
     asset: StellarSdk.Asset.native(),
     amount: "10"
     }))
    

您还应该注意,金额是一个字符串而不是数字。 当处理极小的分数或较大的值时,浮点数学可能会带来很小的不准确性。 由于并非所有系统都有原生的方式来精确表示极小或极小的小数,因此Stellar使用字符串作为可靠的方式来表示任何系统的确切数量。

  1. 或者,您可以将自己的元数据(称为备忘录)添加到事务中。 恒星对这些数据不做任何处理,但您可以将其用于任何您想要的目的。 例如,如果您是代表其他人收款或付款的银行,则可能包括实际付款的人员。

    .addMemo(StellarSdk.Memo.text('Test Transaction'))      
    
  2. 既然事务处理了它所需的全部数据,那么就必须使用秘密种子对它进行加密签名。 这证明数据实际上来自你而不是冒充你的人。

    transaction.sign(sourceKeys);
    
  3. 最后,将它发送到恒星网络!

    server.submitTransaction(transaction);
    

一个很重要的情况你必须知道。就是由于错误,网络条件等原因,您可能无法收到Horizon服务器的响应。在这种情况下,无法确定您的交易状态。 这就是为什么您应该始终将构建的事务(或以XDR格式编码的事务)保存在变量或数据库中,并在您不知道其状态时重新提交。 如果交易已经成功应用于分类帐,Horizon将简单地返回保存的结果,而不会尝试再次提交交易。 只有在交易状态未知的情况下(因此才有可能被纳入分类帐),才会重新提交给网络。

接受付款

实际上,您无需执行任何操作即可将款项收入恒星账户 - 如果付款人向您发送资产的成功交易,这些资产将自动添加到您的账户中

但是,您需要知道有人实际付了钱。 如果您是代表他人接受付款的银行,您需要了解发送给您的内容,以便向预期收款人支付资金。 如果您经营的是零售业务,您需要知道您的客户在向他们交付商品之前实际支付了您的费用。 如果您是带Stellar帐户的自动租赁汽车,则您可能需要确认在您的前排座位上的客户实际付款后才能开启您的引擎。

一个简单的程序,监视网络的付款和打印每一个可能看起来像:

   var StellarSdk = require('stellar-sdk');

   var server = new StellarSdk.Server('https://horizon-testnet.stellar.org');
   var accountId = 'GC2BKLYOOYPDEFJKLKY6FNNRQMGFLVHJKQRGNSSRRGSMPGF32LHCQVGF';

   // Create an API call to query payments involving the account.
   var payments = server.payments().forAccount(accountId);

   // If some payments have already been handled, start the results from the
   // last seen payment. (See below in `handlePayment` where it gets saved.)
   var lastToken = loadLastPagingToken();
   if (lastToken) {
      payments.cursor(lastToken);
   }

   // `stream` will send each recorded payment, one by one, then keep the
   // connection open and continue to send you new payments as they occur.
   payments.stream({
       onmessage: function(payment) {
       // Record the paging token so we can start from here next time.
       savePagingToken(payment.paging_token);

       // The payments stream includes both sent and received payments. We only
       // want to process received payments here.
       if (payment.to !== accountId) {
          return;
       }

        // In Stellar’s API, Lumens are referred to as the “native” type. Other
        // asset types have more detailed information.
        var asset;
        if (payment.asset_type === 'native') {
           asset = 'lumens';
        }
        else {
            asset = payment.asset_code + ':' + payment.asset_issuer;
        }

         console.log(payment.amount + ' ' + asset + ' from ' + payment.from);
     },

     onerror: function(error) {
       console.error('Error in payment stream');
    }
  });

    function savePagingToken(token) {
          // In most cases, you should save this to a local database or file so that
         // you can load it next time you stream new payments.
    }

    function loadLastPagingToken() {
     // Get the last paging token from a local database or file
    }

这个程序有两个主要部分。 首先,您创建一个涉及给定账户的支付查询。 像Stellar中的大多数查询一样,这可能会返回大量的项目,因此API会返回分页令牌,稍后您可以使用该分页令牌从先前离开的同一点开始查询。 在上面的例子中,保存和加载分页标记的函数是空白的,但是在真实应用程序中,您希望将分页标记保存到文件或数据库中,以便在程序出现的情况下, 崩溃或用户关闭它。

     var payments = server.payments().forAccount(accountId);
     var lastToken = loadLastPagingToken();
     if (lastToken) {
       payments.cursor(lastToken);
     }

其次,查询的结果被流式传输。 这是观察付款或其他交易的最简单方式。 每个现有支付都是通过该流逐一发送的。 一旦所有现有付款都已发送完毕,流将保持打开状态,并在发送新付款时发送。

试一试:运行该程序,然后在另一个窗口中创建并提交付款。 你应该看到这个程序记录付款。

	payments.stream({
      onmessage: function(payment) {
     // handle a payment
       }
    });

您还可以按组或页面请求付款。 处理完每一页付款后,您需要申请下一个付款页面,直到没有任何付款。

    payments.call().then(function handlePage(paymentsPage) {
    paymentsPage.records.forEach(function(payment) {
    // handle a payment
     });
      return paymentsPage.next().then(handlePage);
   });

以其他货币进行交易

关于恒星网络的一个惊人的事情是,您可以发送和接收许多类型的资产,例如美元,尼日利亚奈拉,比特币等数字货币,甚至是您自己的新资产。

虽然Stellar的本土资产,流明相当简单,但所有其他资产可以被认为是特定账户发行的信用。实际上,当您在恒星网络上交易美元时,您实际上不会交易美元 - 您从特定账户交易美元。这就是上述例子中的资产既有代码又有发行者的原因。发行人是创建资产的账户的ID。了解哪些帐户发布资产非常重要 - 您需要相信,如果您想在恒星网络上兑换实际美元账单上的美元,发行方将能够向您提供这些资金。正因为如此,你通常只需要信任主要金融机构代表本国货币的资产。

恒星还支持作为一种资产发送并作为另一种资源接收的付款。您可以将奈及利亚奈拉寄给德国的朋友,让他们获得欧元。这些多币种交易可以通过内置的市场机制来实现,人们可以通过该机制提供买入和卖出不同类型资产的报价。恒星将自动找到最好的人兑换货币,以便将奈拉转换成欧元。

目前恒星网络完全是由恒星基金会以外的社区运行。我们希望保证网络不会由恒星基金会操作和管理。恒星基金会贡献开源核心代码,除此之外,社区将会让这个网络更加丰富多彩,富有价值。