# Solana浅析：账户模型与代币标准

By [OKD_Web3_Design](https://paragraph.com/@okd-web3-design) · 2022-09-06

---

![](https://storage.googleapis.com/papyrus_images/376af027ab2cbfdfe29ee0c370dbe4ab50413f1e68327d0e1bde04b08b2b6237.png)

Solana 是一条可扩展的高性能公链，它的创始人 Anatoly Yakovenko 在17年见证了整个ICO的蓬勃发展，当他看到每一笔转账费用高达60美金的时候，就萌生了一个想法，要打造一条手续费低、TPS高，可以容纳很多项目在上面运行的高性能区块链网络。于是他联合前同事 Greg Fitzgerald 开发了一个基于历史证明机制（PoH）的纯开源、抗审查的 Solana 公链网络，在17年发表了白皮书，在次年4月份的时候发布了它的测试网，广大的程序员可以轻松、方便、低廉的在上面部署自己的Dapp。

2020年的3月份 Solana 的 beta主网正式上线，21年7月 FTX 的创始人天才交易员 SBF 选择 Solana 作为他们交易所的底层公链，在这个消息宣布之后，SOL代币的价格一个月内涨了170%，Solana 也迅速走进了大众的视野，整个生态爆发了井喷式的增长。有了顶级资本 a16z 和 Polychain Capital 领衔的3.1亿美元的融资支持后，Solana 更是犹如乘上了一艘东风战舰，发展速度一飞冲天，很多本来选择以太坊的成熟项目开始将目光转向 Solana 生态。

![](https://storage.googleapis.com/papyrus_images/3d9adabc6fcfd84d87ad1854fe54d248030e5528c94f88ad7494b6090ecfd203.png)

Solana 的代币 SOL 目前在加密资产的市值排名中位列第九，最高的时候曾达到500亿美元，被认为是公链之王——以太坊的有力竞争者。它创造的新技术使用户能够在企业级拥有智能合约的快速交易和安全性。截止2021年中，Solana 支持每秒50000笔交易（TPS），并在200个验证节点的帮助下，每400毫秒产生一个新区块，同时保持着接近0的网络费用。

![](https://storage.googleapis.com/papyrus_images/48b71251aefb1ef1d59cd697b0ceb0139ee5ae7c9202612d7434e3e64eb9ab72.png)

在以太坊上，每个智能合约的代码和状态都存储在同一个账户中，Solana 也是基于账户模型的区块链，但是与以太坊和比特币账户模型不同的是 Solana 为了 “保持账户的活跃度（Keep Account Alive）”，它引入了一个称为“租金（Rent）”的存储成本（Storage Cost）的概念。

在Solana 系统上，存在着3种账户：

1.  数据账户：用于存储数据；
    
2.  程序账户：用于存储可执行程序，主要是程序的BPF字节码；
    
3.  原生账户（Native Accounts）：它们代表着Solana 系统中的诸多原生程序（用来维护系统运转、质押和投票等）
    

在数据账户中，又分为两种类型：

*   系统拥有的账户；
    
*   PDA（Program Derived Address）账户，也就是程序的派生账户； 每一个账户都有一个地址（通常是公钥）和一个所有者（程序账户的地址），账户存储的完整字段：
    

![](https://storage.googleapis.com/papyrus_images/a76ba20f8bb8a02eadfa8e111f90bbeea61c3c7d0cd24323f4d952c6f3c4f94a.png)

Solana 的合约与Solidity不同的是 Solana 链上程序的部署是按其账户大小进行定期收费的，目前的费用是2天一收，1K大小约0.01 SOL。如果账户无法支付租金，系统将清除该账号。为了防止账户被删除，用户必须支付租金，也就是存储费。如果用户钱包中持有相当于两年租金的最低余额，那么这个账户可以免交租金。

SOL是 Solana 链的原生代币，该网络的代币标准是SPL，类似于以太坊上的ERC 20和BSC上的BEP 20。在以太坊钱包中，用户可以通过钱包中的ETH地址接收或发送所有基于ERC 20标准铸造的代币，而SPL代币则不能直接流转在 Solana 的原生代币SOL地址。Solana 钱包里面的每个Token 都是一个独立的账户，例如USDC、USDT等对应的都是不同的账户，这是二者间最大的区别所在。

造成这种区别的原因在于Solana一直贯彻的“异步并行”的观念，通过自动验证的各种“异步”处理来最大限度避免交易和验证过程的拥堵，以保证最高的处理性能。进一步理解一下，也就是Solana 在交易时需要通过指令（Instructions）来指定需要读取或者写入的账户列表，通过提前创建这些账户，并且在运行过程中整合所有的交易来实现程序的高效执行。在这样的Token模型中数据的存储都是分开的，而每种Token，每个Token持有⼈都对应着⼀个独⽴的账⼾，这就提供了交易并行处理的可能，即使有⼀万笔交易需要处理，只要交易涉及的账号不同就不会造成拥堵。

在Solana链上，用户还可以运用SPL创建和发行非同质化代币（NFT），而在以太坊上，ERC-20只能创建同质化代币，非同质化代币需要使用ERC-721标准。

与其他大多数区块链不同的是，Solana 将代码与数据完全分离，Solana 链上的程序都是只读或无状态的，所有与程序交互的数据都存储在独立的账户中，并通过指令（Instructions）作为引用传给程序，程序本身存储在账户中，并且被标记为可执行（excitable），这种模型允许一个通用程序进行跨账户操作而不需要额外部署。

指令（Instructions）是 Solana 中最基本的操作单元，每个指令包含：

*   program\_id：程序是基于账户来运行的，被标记为“可执行的账户”会分配给BPF Loader。此帐户的地址称为’ program\_id '，该地址将用于在所有的未来交易中引用程序。
    
*   accounts：存放着读取和写入的账户地址数组
    
*   instruction\_data：与关联的程序定义并解析
    

如果程序检测到交易的目标钱包中没有该代币帐户，会执行`createInitializeAccountInstruction` 指令，创建一个 Associated Token Address (ATA)。

    // 2. ATA
      {
        let ata = await getAssociatedTokenAddress(
          mintPubkey, // mint
          alice.publicKey, // owner
          false // allow owner off curve
        );
        console.log(`ata: ${ata.toBase58()}`);
    
        let tx = new Transaction();
        tx.add(
          createAssociatedTokenAccountInstruction(
            feePayer.publicKey, // payer
            ata, // ata
            alice.publicKey, // owner
            mintPubkey // mint
          )
        );
    
        console.log(`create ata txhash: ${await connection.sendTransaction(tx, [feePayer])}`);
      }
    })();
    

这个ATA地址其实就是PDA程序派生帐户，它的账户地址虽然与SOL钱包地址不同，但是程序可以通过`findAssociatedTokenAddress` 方法推导出该派生账户关联的钱包地址，所以用户只需要知道自己SOL钱包的主地址即可。

    import { PublicKey } from '@solana/web3.js';
    import { TOKEN_PROGRAM_ID } from '@solana/spl-token';
    
    const SPL_ASSOCIATED_TOKEN_ACCOUNT_PROGRAM_ID: PublicKey = new PublicKey(
      'ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL',
    );
    
    async function findAssociatedTokenAddress(
        walletAddress: PublicKey,
        tokenMintAddress: PublicKey
    ): Promise<PublicKey> {
        return (await PublicKey.findProgramAddress(
            [
                walletAddress.toBuffer(),
                TOKEN_PROGRAM_ID.toBuffer(),
                tokenMintAddress.toBuffer(),
            ],
            SPL_ASSOCIATED_TOKEN_ACCOUNT_PROGRAM_ID
        ))[0];
    }
    

Wrapped SOL代币的生成机制跟其他帐户有亿点点不一样，它采用了一种特殊的“Native Mint”的方式，通过公钥 `So11111111111111111111111111111111111111112` 来创建。其他代币的账户如果需要关闭，一定要先将余额全部转出，然后才可以执行关闭帐户的指令，但是WSOL没有这种限制，可以随时关闭帐户，余额和租金会一起兑换成SOL退回钱包。

![](https://storage.googleapis.com/papyrus_images/caa13393cd71ea577e7f1fa711b72e3a925a83d58fc3c66b30417b0e8c917a64.png)

在交易过程中，可能会产生一些临时的WSOL帐户，这些临时账户（Temporary Account）跟ATA帐户不同的是，它们虽然都是WSOL，但是相互之间独立，不共用一个账户。

    let tmpAccount = Keypair.generate();// wrapped sol's decimals is 9let amount = 1e9;let tx1 = new Transaction();
      tx1.add(
        SystemProgram.createAccount({
          fromPubkey: FEE_PAYER.publicKey,
          newAccountPubkey: tmpAccount.publicKey,
          space: SPLToken.AccountLayout.span,
          lamports: (await SPLToken.Token.getMinBalanceRentForExemptAccount(CONNECTION)) + amount, // rent + amount
          programId: SPLToken.TOKEN_PROGRAM_ID,}),
        SPLToken.Token.createInitAccountInstruction(
          SPLToken.TOKEN_PROGRAM_ID,
          SPLToken.NATIVE_MINT,
          tmpAccount.publicKey,ALICE.publicKey
        ),
        SPLToken.Token.createTransferInstruction(
          SPLToken.TOKEN_PROGRAM_ID,
          tmpAccount.publicKey,
          ata,ALICE.publicKey,[],
          amount
        ),
        SPLToken.Token.createCloseAccountInstruction(
          SPLToken.TOKEN_PROGRAM_ID,
          tmpAccount.publicKey,ALICE.publicKey,ALICE.publicKey,[]));
      tx1.feePayer = FEE_PAYER.publicKey;console.log(`tx1 txhash: ${await CONNECTION.sendTransaction(tx1, [FEE_PAYER, tmpAccount, ALICE])}`);// 2. SyncNative
    

当一笔交易（Transaction）被提交到链上时，Solana 的接收程序将执行其中包含的每个指令，并对交易过程中涉及到的指定账户进行操作，任何想要在账户中进行交易的行为需要账户持有人（是Holder，不是Owner）的签名。为了更好的满足 Solana 链的多跳DEX和跨链交易的需求，我们需要实现单笔签名进行批量交易的技术方案，即一次签名后按顺序发起三笔交易：

1.  创建账户（Create Account）
    
2.  交易（Swap）
    
3.  关闭帐户（Close Account）
    

其中潜在的风险点是第三步关闭帐户有可能会执行失败，导致用户在交易过程中为一些临时的WSOL账户支付了多余的租金，而且用户也无法在DEX中交易这部分WSOL，所以我们需要在交易完成时，给用户提供一个手动关闭帐户的入口，帮助用户赎回这些临时WSOL账户占有的租金。

![](https://storage.googleapis.com/papyrus_images/b9401725dab54817051279d8e858909adb468ee7b10488a6d2c59257614654f8.png)

Solana 链上的交易聚合器 1Sol 为用户提供了批量unwrap Wrapped SOL的小工具（Toolkit），但是这个过程会将你帐户中的ATA WSOL帐户一起关闭，等于是彻底将帐户中的WSOL一起消灭。我们的本意是希望帮助用户将关闭帐户失败的这些临时WSOL帐户关闭，而不影响其原来的WSOL余额，所以这里在技术方案上就要对这些不同的WSOL账户地址加以区分。

![](https://storage.googleapis.com/papyrus_images/44d2684d432f9615c2f58e2b9f06ed11fa42829fc5411061957ef1cf2c9006fe.png)

OKX DEX目前已接入 Solana 公链，并于今年7月上线支持 Solana 链上的代币交易。目前已接入Solana 链上6个DEX（ORCA、Token Swap、One Moon、Aldrin v2、Aldrin v1、Saber），为币币交易提供了丰富的流动性。后续接入SWFT跨链桥后，可以全面支持Solana链与其他EVM系之间的跨链交易，打破公链之间的孤岛效应。

![](https://storage.googleapis.com/papyrus_images/7478180517a0c844d52cff2eb50fea98f7f6d02f1c91f041ac5734638f1bdf57.png)

Solana 自诞生以来，一直秉持着开源、包容的设计理念，希望为区块链网络提供更强的可扩展性，促进DeFi应用的繁荣发展，与更多公链实现互连互通。20年10月上线的 Wormhole 跨链桥打通了Solana 和以太坊这两个功能强大的公链生态，用户可以便捷的将自己的ERC 20资产与SPL互相转换，为应用的迁移、跨链生态的繁荣提供了强有力的支持。通过这样的强强联合，未来的链上会是一个更自由、更广阔的新世界，我们也期待着，可以一起见证区块链网络更多的可能性。

![](https://storage.googleapis.com/papyrus_images/e725f8ceb254da5c7e22603feadcada62fd6abdedff88357380c29bc6bc58a95.png)

Reference
---------

1.  Associated Token Account Program：[https://spl.solana.com/associated-token-account](https://spl.solana.com/associated-token-account)
    
2.  Solana WIKI - Account Model：[https://solana.wiki/zh-cn/docs/account-model/](https://solana.wiki/zh-cn/docs/account-model/)
    
3.  Solana Web3 Example：[https://yihau.github.io/solana-web3-demo/](https://yihau.github.io/solana-web3-demo/)
    
4.  Wrapped SOL (wSOL)：[https://docs.jup.ag/notes/wrapped-sol-wsol：https://docs.jup.ag/notes/wrapped-sol-wsol](https://docs.jup.ag/notes/wrapped-sol-wsol%EF%BC%9Ahttps://docs.jup.ag/notes/wrapped-sol-wsol))
    
5.  Can't unwrap SOL tokens without closing WSOL account：[https://github.com/solana-labs/solana-program-library/issues/2748](https://github.com/solana-labs/solana-program-library/issues/2748)
    
6.  一文了解SPL：兼顾性能和扩展性的Solana代币标准：[https://www.defidaonews.com/media/6667823](https://www.defidaonews.com/media/6667823)
    
7.  Solana钱包常见问题：[https://xueqiu.com/5676556297/179162049](https://xueqiu.com/5676556297/179162049)
    
8.  刪除Solana錢包中不需要的Token賬戶退還租金的方法：[https://bitcoinkol.com/archives/34](https://bitcoinkol.com/archives/34)
    
9.  Solana之旅6：Solana存储费与交易剖析：[https://blog.csdn.net/DongAoTony/article/details/124548323](https://blog.csdn.net/DongAoTony/article/details/124548323)
    
10.  建議收藏：Solana常見問題解決方案：[https://www.panewslab.com/zh\_hk/articledetails/D09343257.html](https://www.panewslab.com/zh_hk/articledetails/D09343257.html)

---

*Originally published on [OKD_Web3_Design](https://paragraph.com/@okd-web3-design/solana)*
