130 Matching Annotations
  1. Feb 2024
    1. MetaMask injects the provider API into websites visited by its users using the window.ethereum provider object
    1. It is possible to use get on sub-objects. This has the benefit of not re-computing when properties of the parent object are updated

      从子集驱动的对象,子集发生变化时候会进行计算,父集的其他属性变化时候,不进行计算

    2. derive

      派生出来的还是proxy

    1. <dialog bind:this={dialog} on:close={() => (showModal = false)} on:click|self={() => dialog.close()}>

      ```js <dialog bind:this={dialog} // 生成引用 on:close={() => (showModal = false)} // 监听事件 on:click|self={() => dialog.close()} // 调用引用上的close方法

      ```

    1. <Hoverable let:hovering={active}>

      在这段 Svelte 代码中,let:hovering={active} 是一种特殊的语法,<span style="color:red">它用于将一个子组件(在这个例子中是 Hoverable)的内部变量或者状态暴露给它的父组件。这样做可以让父组件根据子组件的状态来改变自己的行为或者渲染。</span>

      在 Svelte 中,let: 指令允许你在父组件中声明一个块级变量,这个变量的值是从子组件的相应属性或者变量中获取的。

      在你的例子中,Hoverable 组件可能有一个内部的响应式变量(可能是一个 writable 或者 derived store),这个变量的名字是 hovering。这个变量用于追踪鼠标是否悬停在某个元素上。

      通过使用 let:hovering={active},你在父组件中创建了一个名为 active 的新变量,它的值与 Hoverable 组件中的 hovering 变量同步。这样,父组件就可以根据 active 的值来决定如何渲染:如果 active 为真(即鼠标正在悬停在 Hoverable 组件上),它会渲染一条消息说 "I am being hovered upon.";如果 active 为假,它会提示用户将鼠标悬停在上面。

      这种模式是 Svelte 的一个强大特性,它允许组件间的紧密协作,同时保持了组件的封装性。通过这种方式,Hoverable 组件可以控制父组件的行为,而不需要直接操作父组件的状态,这也有助于维护组件间的清晰界限。

    1. Only available in Trading Platform. Get a watched value that can be used to read/write/subscribe to the state of the crosshair sync between charts

      仅在交易平台中可用。获取一个监视值,该值可用于读取/写入/订阅图表之间的十字准线同步状态

  2. Jan 2024
    1. When the attribute name and value match (name={name}), they can be replaced with {name}

      简写

    1. <svelte:component>

    2. The <svelte:self> element allows a component to include itself, recursively.

    1. connectedCallback

    2. Passing null, undefined or nothing to an @ expression will cause any existing listener to be removed.

    3. but events can also be used to communicate information from the listener back to the dispatcher

      将监听器中的值,传递到事件派发器中

    4. This typically means that a component should dispatch an event in response to another event to which it is listening.

      监听:@mylogin=${this._loginListener}

      触发:this.dispatchEvent(new CustomEvent('mylogin', options));

    5. Retargeting can interfere with event delegation, and to avoid it, event listeners can be added to the component's shadow root itself. Since the shadowRoot is not available in the constructor, event listeners can be added in the createRenderRoot method as follows. Please note that it's important to make sure to return the shadow root from the createRenderRoot method.

      重定向可能会干扰事件委派,为了避免这种情况,可以将事件侦听器添加到组件的影子根本身。由于 在 shadowRoot 中不可用 constructor ,因此可以在 createRenderRoot 方法中添加事件侦听器,如下所示。请注意,请务必确保从 createRenderRoot 该方法返回影子根。

    1. Renders the latest value from an AsyncIterable into the DOM as it is yielded.

      异步替换内容

    2. Appends values from an AsyncIterable into the DOM as they are yielded.

      向列表追加内容

    3. Renders placeholder content until one or more promises resolve.

      渲染占位符内容,直到一个或多个承诺得到解决。

      同React Suspense

    4. Sets an attribute or property if it differs from the live DOM value rather than the last-rendered value.

      就是输入结束后,才更新渲染,输入过程中不更新渲染,有点类似防抖动?

      实际上,live 指令的工作方式与防抖(debounce)不同。防抖是一种控制函数调用频率的技术,它会在指定的时间内延迟函数的执行。如果在这个延迟期间再次触发了函数,延迟时间会重新计算。这通常用于控制如输入框这样的事件,确保在用户停止输入后才执行某些操作,比如搜索查询。

      live 指令的目的是确保用户界面上的值(例如输入框中的文本)与后端数据保持一致。当使用live指令时,只有当数据模型中的值和输入框的当前值不一致时,输入框的值才会更新。这样做的目的是防止在用户输入的过程中,由于数据模型的变化而引起的不必要的DOM更新,这可能会干扰用户的输入体验。

      使用live指令时,如果用户正在输入,而数据模型的值发生了变化,这个变化不会立即反映到输入框上,除非用户的输入已经完成,并且他们输入的值与数据模型的新值不匹配。这样,用户的输入体验不会被打断,因为输入框中的值不会在他们输入时发生变化。

      所以,live指令关注的是如何在用户输入和数据模型变化之间保持平衡,而不是延迟事件的执行,它是为了避免在用户输入时更新DOM,而不是延迟函数调用。

    5. Only re-evaluates the template when one of its dependencies changes, to optimize rendering performance by preventing unnecessary work.

      performance

      仅当模板的依赖项之一发生更改时才重新评估模板,以通过防止不必要的工作来优化渲染性能。

    6. Sets an attribute if the value is defined and removes the attribute if undefined.

      针对的是attribute

    1. accessor

    2. @queryDefines a property that returns an element in the component template.Shadow DOM@queryAllDefines a property that returns a list of elements in the component template.Shadow DOM@queryAsyncDefines a property that returns a promise that resolves to an element in the component template.Shadow DOM@queryAssignedElementsDefines a property that returns the child elements assigned to a specific slot.Shadow DOM@queryAssignedNodesDefines a property that returns the child nodes assigned to a specific slot.Shadow DOM

    1. wallet_watchAsset

      请求用户在 MetaMask 中跟踪指定的令牌。返回一个布尔值,指示是否已成功添加令牌。添加后,令牌与使用旧方法(如集中式注册表)添加的令牌无法区分。由 EIP-747 引入

    1. signTransaction
      1. prepareTransactionRequest
      2. signTransaction
      3. sendRawTransaction

      这三个联合使用

    1. sendRawTransaction
      1. prepareTransactionRequest
      2. signTransaction
      3. sendRawTransaction

      这三个联合使用

    1. prepareTransactionRequest
      1. prepareTransactionRequest
      2. signTransaction
      3. sendRawTransaction

      这三个联合使用

    1. Formatters

      主要用于格式化,排除一些用不到的字段

    1. Destroys a Filter that was created from one of the following Actions:

      销毁通过以下操作之一创建的过滤器

    1. createPendingTransactionFilter

      在实际应用中,开发者可以根据他们的需求选择合适的过滤器类型: - 如果需要<span style="color:red"> 获取新区块的通知</span>,使用 eth_newBlockFilter。 - 如果需要<span style="color:red">获取智能合约的事件日志</span>,使用 eth_newFilter。 - 如果需要<span style="color:red">获取新的挂起交易的通知</span>,使用 eth_newPendingTransactionFilter

    1. createEventFilter

      在实际应用中,开发者可以根据他们的需求选择合适的过滤器类型: - 如果需要<span style="color:red"> 获取新区块的通知</span>,使用 eth_newBlockFilter。 - 如果需要<span style="color:red">获取智能合约的事件日志</span>,使用 eth_newFilter。 - 如果需要<span style="color:red">获取新的挂起交易的通知</span>,使用 eth_newPendingTransactionFilter

    1. createBlockFilter

      在实际应用中,开发者可以根据他们的需求选择合适的过滤器类型: - 如果需要<span style="color:red"> 获取新区块的通知</span>,使用 eth_newBlockFilter。 - 如果需要<span style="color:red">获取智能合约的事件日志</span>,使用 eth_newFilter。 - 如果需要<span style="color:red">获取新的挂起交易的通知</span>,使用 eth_newPendingTransactionFilter

    1. getLogs

      在使用范围和目的上,这三个函数各有其适用场景:

      • 如果你想要获取一次性的历史日志数据,使用eth_getLogs是最合适的。
      • 如果你<span style="color:red"> 想要创建一个长期的监听过程</span>,可以使用eth_newFilter创建一个过滤器,然后定期调用eth_getFilterChanges来获取更新。
      • 如果你需要<span style="color:red">获取自过滤器创建以来的所有日志</span>,可以使用eth_getFilterLogs
    1. getFilterLogs

      在使用范围和目的上,这三个函数各有其适用场景:

      • 如果你想要获取一次性的历史日志数据,使用eth_getLogs是最合适的。
      • 如果你<span style="color:red"> 想要创建一个长期的监听过程</span>,可以使用eth_newFilter创建一个过滤器,然后定期调用eth_getFilterChanges来获取更新。
      • 如果你需要<span style="color:red">获取自过滤器创建以来的所有日志</span>,可以使用eth_getFilterLogs
    1. getFilterChanges

      在使用范围和目的上,这三个函数各有其适用场景:

      • 如果你想要获取一次性的历史日志数据,使用eth_getLogs是最合适的。
      • 如果你<span style="color:red"> 想要创建一个长期的监听过程</span>,可以使用eth_newFilter创建一个过滤器,然后定期调用eth_getFilterChanges来获取更新。
      • 如果你需要<span style="color:red">获取自过滤器创建以来的所有日志</span>,可以使用eth_getFilterLogs
    1. estimateMaxPriorityFeePerGas

      用来预估每个gas给矿工多少小费(单位wei)

      返回可能包含在下一个区块中的交易的每项 Gas 的最大优先费(以 wei 为单位)的估计值。

      如果在客户端链上设置了 chain.fees.defaultPriorityFee 或覆盖链,它将使用该值。

      否则,该操作将调用 eth_maxPriorityFeePerGas(如果支持)或根据当前区块的每个 Gas 基本费用 + Gas 价格手动计算每个 Gas 的最大优先费

    1. estimateGas

      用来设定 gasLimit的

      如果用 ether.js 来完整实现这些计算,改如何书写

      要使用 Ethers.js 来实现这些计算,你需要做几件事情:

      1. 连接到以太坊网络。
      2. 获取最新区块的基础费用 (baseFeePerGas)。
      3. 估算交易的 gasLimit(如果不是简单的 ETH 转账)。
      4. 计算或获取推荐的 maxPriorityFeePerGasmaxFeePerGas

      下面是一个基本的代码示例,展示如何使用 Ethers.js 完成这些步骤:

      ```javascript const { ethers } = require('ethers');

      // 连接到以太坊提供者,例如使用 Infura const provider = new ethers.providers.JsonRpcProvider('https://mainnet.infura.io/v3/YOUR_INFURA_PROJECT_ID');

      // 假设你已经有了交易的详情 const transactionDetails = { to: '0xRecipientAddress', // 接收方地址 value: ethers.utils.parseEther('1.0'), // 转账数量,例如 1 ETH // 如果是智能合约交易,你可能需要添加 data 字段 // data: "0x", // 智能合约调用数据 };

      async function calculateTransactionCost() { // 获取最新区块的基础费用 const latestBlock = await provider.getBlock('latest'); const baseFeePerGas = latestBlock.baseFeePerGas;

      // 估算交易的 gas 量 const gasLimit = await provider.estimateGas(transactionDetails);

      // 获取当前网络条件下推荐的 maxPriorityFeePerGas // 注意:这里需要一个API来获取推荐值,或者你可以自己设定一个值 const maxPriorityFeePerGas = ethers.utils.parseUnits('2', 'gwei'); // 假设为 2 Gwei

      // 计算 maxFeePerGas,通常是 baseFeePerGas + maxPriorityFeePerGas // 这里我们假设矿工费用是 baseFeePerGas 的两倍加上 maxPriorityFeePerGas const maxFeePerGas = baseFeePerGas.mul(2).add(maxPriorityFeePerGas);

      // 设置交易的费用选项 transactionDetails.gasLimit = gasLimit; transactionDetails.maxPriorityFeePerGas = maxPriorityFeePerGas; transactionDetails.maxFeePerGas = maxFeePerGas;

      // 计算总的交易费用 const totalTransactionFee = maxFeePerGas.mul(gasLimit);

      // 输出结果 console.log(Gas Limit: ${gasLimit.toString()}); console.log(Base Fee Per Gas: ${ethers.utils.formatUnits(baseFeePerGas, 'gwei')} Gwei); console.log(Max Priority Fee Per Gas: ${ethers.utils.formatUnits(maxPriorityFeePerGas, 'gwei')} Gwei); console.log(Max Fee Per Gas: ${ethers.utils.formatUnits(maxFeePerGas, 'gwei')} Gwei); console.log(Total Transaction Fee (Max): ${ethers.utils.formatEther(totalTransactionFee)} ETH);

      // 如果你需要发送交易,你可以在这里继续调用 provider.sendTransaction(...) }

      calculateTransactionCost().catch(console.error); ```

      请注意,上述代码中的 maxPriorityFeePerGasmaxFeePerGas 是估计值。在实际应用中,你可能需要根据网络的拥堵情况动态调整这些值,或者使用第三方服务如 Etherscan 或其他可靠的 gas tracker 来获取实时的 gas 价格推荐。

      此外,maxFeePerGas 的计算在这里是简化的。实际情况下,你可能需要考虑更多的因素,比如当前网络的拥堵程度和预期的交易确认速度。在某些情况下,你可能希望将 maxFeePerGas 设置得更高以确保交易能快速被打包。

    1. maxFeePerGas

      计算 maxFeePerGas,通常是 baseFeePerGas + maxPriorityFeePerGas

    2. legacy

      eip1559之前的版本

    1. Returns the hash (of the event signature) for a given event definition.

      返回给定事件定义的(事件签名的)哈希值

      问题

    1. Retrieves the size of the value (in bytes).

      ```ts export function size(value: Hex | ByteArray) { if (isHex(value, { strict: false })) return Math.ceil((value.length - 2) / 2) return value.length }

      ```

    1. Returns a section of the hex or byte array given a start/end bytes offset.

    2. The end offset (in bytes).

      结束偏移量(以字节为单位)

    1. Checks if the given addresses (checksummed) are equal.

      先判断是不是地址,然后都转化成小写判断是否相等

    1. Extracts a type-safe chain by ID from a set of chains.

      通过id准确提取链数据

      源代码参考 /Users/haotian.chen/Desktop/temp/wagmi-relate/wagmi/playgrounds/vite-react`

    1. repriced

      🌹加速交易,如果我交易完成了,我再点击加速交易会消耗gas吗?

      当你在以太坊网络上发起一个交易后,有时可能会因为设置的 Gas 价格太低而导致交易确认速度缓慢。在这种情况下,"加速交易" 是一种常见的做法,它通常涉及发送另一个具有相同 nonce 但更高 Gas 价格的交易。这样做可以提高矿工接受交易的概率,从而加快交易的确认速度。

      如果你的原始交易已经完成(即已经被矿工打包进区块并确认),再尝试加速交易是没有意义的,因为交易已经最终确定,无法被修改或替换。

      在这种情况下,如果你发送了一个具有更高 Gas 价格的交易,但使用了一个新的 nonce(因为每个成功的交易都会增加账户的 nonce),这个新的交易将被视为一个全新的交易,而不是对原始交易的加速。如果这个新的交易有足够的 Gas 价格并且发送到了网络,它将消耗 Gas 并执行其指定的操作。

      如果你试图使用相同的 nonce 发送一个新的交易来加速一个已经完成的交易,网络将简单地忽略这个新的交易请求,因为相同 nonce 的交易已经存在于区块链中。在这种情况下,你不会消耗额外的 Gas,因为新的交易不会被矿工接受。

      总结一下:

      • 如果原始交易已经完成,再尝试加速是没有作用的,也不会消耗额外的 Gas。
      • 如果你发送了一个具有新 nonce 的新交易,它将被视为一个全新的交易,并且如果被矿工接受,将消耗 Gas。
    1. sending transactions to networks

      🌹我要是在前端网页中进行调用,调用哪个api?

      在前端网页中进行以太坊交易调用时,出于安全考虑,你应该使用 eth_sendRawTransaction API。这是因为在前端环境中直接使用 eth_sendTransaction 会要求用户的私钥在前端暴露,这是非常不安全的。

      使用 eth_sendRawTransaction 的流程通常涉及以下步骤:

      1. 创建交易对象:你需要构造一个交易对象,包含了交易的所有必要信息,如接收者地址(to)、发送的金额(value)、数据(data,如果是调用智能合约函数)、gasgasPrice

      2. 签名交易:在用户的浏览器中,使用JavaScript库(如ethers.jsweb3.js)来对交易进行签名。用户的私钥用于签名过程,但不会离开用户的设备。

      3. 发送原始交易:将签名的交易(现在是一个原始的十六进制字符串)通过 eth_sendRawTransaction 发送到以太坊网络。

      例如,如果你使用 web3.js 库,流程可能如下:

      javascript web3.eth.accounts.signTransaction(transactionObject, privateKey) .then(signedTx => web3.eth.sendSignedTransaction(signedTx.rawTransaction)) .then(receipt => console.log("Transaction receipt: ", receipt)) .catch(err => console.error(err));

      在这个例子中,transactionObject 包含了交易的细节,privateKey 是用户的私钥,用于签名交易。注意,私钥是在用户的设备上使用,并且不应该通过网络发送或在服务器上存储。

      如果你使用的是MetaMask或其他以太坊钱包插件,它们内置了安全的签名机制,你可以通过插件提供的API进行交易而不需要直接处理私钥。例如,使用 MetaMask 时,你可以这样调用:

      javascript ethereum.request({ method: 'eth_sendTransaction', params: [transactionObject], }).then((txHash) => console.log(txHash)) .catch((error) => console.error);

      在这种情况下,MetaMask 会处理交易的签名过程,用户只需确认交易即可。这是因为 MetaMask 作为浏览器扩展,其背后的环境比普通的前端页面更加安全,可以安全地管理用户的私钥。

    2. sendTransaction

      内部封装了两个eth_的api eth_sendTransaction eth_sendRawTransaction

      eth_sendTransactioneth_sendRawTransaction 是以太坊 JSON-RPC 接口的两个调用方法,它们用于提交交易,但它们的使用方式和目的有所不同。

      1. eth_sendTransaction

      eth_sendTransaction 用于创建和发送一个由节点管理的账户的交易。当你调用这个方法时,你提供一个交易对象,包含了如 from, to, value, data, gas, gasPrice 等字段。节点(通常是一个以太坊客户端,如Geth或Parity)将使用本地存储的私钥来签名交易。

      这个方法要求你的以太坊节点拥有发送者账户的私钥,并且节点必须解锁该账户以便签名交易。因此,这种方法通常不推荐用于前端应用或任何不安全的环境,因为它要求节点具有访问和管理私钥的能力。

      示例调用: json { "method": "eth_sendTransaction", "params": [{ "from": "0x...", "to": "0x...", "value": "0x...", "gas": "0x...", "gasPrice": "0x...", "data": "0x..." }], "id": 1, "jsonrpc": "2.0" }

      1. eth_sendRawTransaction

      eth_sendRawTransaction 用于发送一个已经完全在外部签名的交易。这意味着交易的创建、签名和序列化(编码为十六进制字符串)是在节点外部完成的,节点不需要访问账户的私钥。

      这个方法更加安全,特别是在客户端或服务端环境中,因为你不需要将私钥暴露给节点。你只需在一个安全的环境中(例如用户的浏览器或后端服务)使用私钥签名交易,然后将签名的交易(十六进制字符串)发送给节点。

      示例调用: json { "method": "eth_sendRawTransaction", "params": ["0x签名的交易数据..."], "id": 1, "jsonrpc": "2.0" }

      总结来说,eth_sendTransaction 适用于节点有权访问私钥的场景,而 eth_sendRawTransaction 更适用于需要保持私钥安全的场景,如客户端钱包或服务端应用程序。实际开发中,由于安全性的考虑,通常会使用 eth_sendRawTransaction

    1. "m/44'/60'/${string}"

      🙋比如metamask钱包,生成的address 是以怎样的path生成的?

      MetaMask 钱包遵循 BIP-44 标准来生成地址。BIP-44 是一种层次性确定性(HD)钱包结构,它允许从单一的种子生成多个币种、账户以及地址。MetaMask 主要支持以太坊及其兼容网络,因此,生成地址的路径通常遵循以下模式:

      m / purpose' / coin_type' / account' / change / address_index

      在这个路径中:

      • purpose 通常固定为 44',表示遵循 BIP-44 的结构。
      • coin_type 对于以太坊,这个值固定为 60'
      • account 表示账户的索引号,从 0' 开始递增。
      • change 用于以太坊,这个值通常是 0,因为以太坊不像比特币一样区分找零地址和接收地址。
      • address_index 是地址的索引号,从 0 开始递增。

      所以,MetaMask 生成第一个以太坊地址的路径通常是:

      m / 44' / 60' / 0' / 0 / 0

      这表示:

      • 使用 BIP-44 标准。
      • 用于以太坊(币种类型 60)。
      • 第一个账户(账户索引为 0)。
      • 外部链(用于接收资金,因此 change 为 0)。
      • 第一个地址(地址索引为 0)。

      当你在 MetaMask 创建更多地址时,address_index 会递增(例如,第二个地址是 m / 44' / 60' / 0' / 0 / 1),但其他部分保持不变。如果你创建了一个新账户,那么 account 部分会递增(例如,第二个账户的第一个地址是 m / 44' / 60' / 1' / 0 / 0)。

      🙋有个问题,我换链创建钱包会有什么影响?

      当您在 MetaMask 或其他类似的多链钱包中“换链”时,通常是指您在钱包软件中切换到另一个区块链网络,例如从以太坊主网切换到 Binance Smart Chain (BSC)、Polygon、Avalanche 或其他兼容的网络。

      这里有几个方面需要注意:

      1. 地址重用:大多数基于以太坊的网络(EVM兼容网络)都使用相同的地址格式。这意味着,即使您切换到另一个链,您的账户地址通常会保持不变。这是因为您的私钥和它派生出的地址在这些网络中都是有效的。

      2. 网络设置:每个区块链网络都有其特定的配置,如网络ID、RPC URL等。当您在钱包中切换链时,钱包会自动调整这些设置以便与所选网络进行交互。

      3. 资产和交易:不同链上的资产是独立的。例如,ETH在以太坊主网上是原生资产,而在BSC上则是一种被称为Binance-Peg Ethereum Token (BETH) 的封装资产。因此,当您切换链时,钱包会显示该链上的资产和交易记录。

      4. 燃料费和交易:每个链都有自己的燃料费(Gas fees)结构和代币。例如,在以太坊上进行交易需要消耗ETH作为燃料费,在BSC上则需要BNB。切换链意味着您需要拥有相应链的本地货币来支付交易费用。

      5. 智能合约和互操作性:不同链上的智能合约是独立部署的,尽管许多项目会在多个链上部署相同的合约代码。切换链时,您将与每个特定链上的合约进行交互。这也意味着某些操作,如代币交换或质押,需要在相应链上进行。

      6. 安全性和隐私:尽管地址可能在不同链上重用,但您的交易记录和余额在每个链上是独立的。这可能会对您的隐私产生影响,因为如果有人知道您的地址,他们可以在每个链上追踪您的资产和交易。

      总的来说,换链创建钱包并不会改变您的钱包地址或私钥,但会改变您与之交互的区块链网络,每个网络都有其独特的特性和要求。始终确保您了解正在使用的网络的特点,以及如何安全地管理您的资产。

    1. fromMasterSeed fromExtendedKey fromJSON

      在讨论加密货币钱包,特别是分层确定性(HD)钱包的上下文中,fromMasterSeedfromExtendedKeyfromJSON 是创建或恢复钱包的不同方法,每种方法都基于不同类型的输入数据。下面是这三种方法的简要说明和它们之间的区别:

      1. fromMasterSeed

      fromMasterSeed 方法用于从一个主种子(Master Seed)创建一个新的 HD 钱包。主种子通常是由一组助记词(根据 BIP-39 标准)生成的,这些助记词在用户创建钱包时生成并记录下来。当使用 fromMasterSeed 方法时,你需要提供这个种子(或由助记词生成的种子),然后钱包软件会使用这个种子来生成根私钥和链码,进而生成整个密钥树。

      2. fromExtendedKey

      fromExtendedKey 方法用于从一个扩展密钥(Extended Key)恢复 HD 钱包。扩展密钥可以是扩展公钥(xPub)或扩展私钥(xPrv)。扩展密钥包含了密钥信息和链码,允许钱包派生出子密钥。使用扩展公钥,你可以生成钱包的所有公钥和接收地址,但不能生成对应的私钥,因此只能用于监视钱包。使用扩展私钥,你可以生成整个密钥树,包括私钥,因此可以完全控制钱包。

      3. fromJSON

      fromJSON 方法是从一个 JSON 格式的数据恢复钱包。这个 JSON 数据通常包含了钱包的所有必要信息,如私钥、公钥、地址、元数据等。这种方法通常用于软件之间的钱包迁移,或者在钱包软件的不同版本之间恢复钱包。输入的 JSON 数据必须是之前导出的钱包数据,以确保可以正确恢复所有相关信息。

      总结

      • fromMasterSeed 基于主种子创建新钱包,适用于初始创建钱包。
      • fromExtendedKey 基于扩展密钥恢复钱包,适用于已有钱包的完整或只读恢复。
      • fromJSON 基于 JSON 数据恢复钱包,适用于跨软件或版本的钱包迁移。

      每种方法的使用取决于用户的具体需求和拥有的备份信息类型。在实际应用中,用户应该选择最适合其当前情况的恢复方法。

    2. Hierarchical Deterministic (HD)

      分层确定性钱包(Hierarchical Deterministic Wallets,简称 HD Wallets),是一种加密货币钱包,它能够从一个单一的种子生成一整套密钥。这种钱包的工作原理基于比特币改进建议 32(BIP-32)和 BIP-44。HD 钱包的主要优势在于它们的便捷性和安全性。

      HD 钱包的关键特点:

      • 分层密钥生成:HD 钱包可以创建一个密钥树,从一个根密钥(种子)出发,按照层级结构生成多个子密钥。

      • 种子短语:HD 钱包通常使用一组随机单词(助记词)来生成根密钥,这组助记词是 BIP-39 标准的一部分,用户可以记忆或记录下这些单词以备份和恢复钱包。

      • 确定性:这意味着从相同的种子出发,总是可以生成相同的密钥序列。这对于备份和恢复钱包至关重要。

      • 多地址钱包:用户可以为不同的交易和目的生成多个地址,增加隐私。

      • 跨货币和应用兼容性:同一个 HD 钱包可以用来管理多种不同的加密货币,并且可以与多个应用程序兼容。

      HD 钱包的工作原理:

      1. 生成种子:一切从生成一个随机的种子(通常是 128位或 256位的随机数)开始。这个种子通常通过助记词的形式呈现给用户。

      2. 根私钥和链码:种子通过哈希函数生成根私钥和链码。链码用于生成子密钥。

      3. 密钥派生:使用根私钥和链码,可以创建一个树状结构的密钥序列。每个节点都可以生成多个子节点,每个子节点又可以生成自己的子节点,依此类推。

      4. 路径表示法:BIP-44 提出了一种标准的路径表示法,用于确定密钥树中的特定位置。例如,m/44'/0'/0'/0/1 表示一个特定的密钥路径。

      5. 使用:用户可以使用派生出的地址来接收和发送加密货币。每个地址都有对应的私钥,而这些私钥都是由同一个种子生成的,因此只需要备份种子即可恢复整个钱包。

      安全性:

      HD 钱包的安全性在于,即使某些私钥或地址被泄露,攻击者也无法计算出根密钥或其他子密钥。此外,由于所有的密钥都是由一个种子生成的,用户只需要确保这个种子的安全性,而不需要单独备份每个私钥。

      备份与恢复:

      备份 HD 钱包相对简单,只需备份种子短语(助记词)。恢复钱包时,只要输入这个种子短语,就能重新生成所有的密钥和地址。

      HD 钱包是现代加密货币钱包的一个重要进步,它们提供了更好的安全性、便捷性和灵活性。

    1. watchPendingTransactions

      基于定时器实现

      eth_newpendingtransactionfilter

      eth_newPendingTransactionFilter 是 Ethereum JSON-RPC API 的一部分,它用于创建一个新的过滤器,这个过滤器会通知调用者有关网络中出现的新的待处理交易。"待处理"交易是指已经被网络节点接收但还未被包含在一个区块中的交易。

      当你调用这个方法时,它会立即返回一个过滤器ID。你可以使用这个ID来调用 eth_getFilterChanges,这个方法将返回自上次轮询以来进入待处理状态的所有交易的哈希列表。这对于那些需要实时监控网络交易活动的应用程序或服务来说非常有用,比如钱包服务或交易监控工具。

      下面是一个 eth_newPendingTransactionFilter 调用的示例:

      json { "jsonrpc": "2.0", "method": "eth_newPendingTransactionFilter", "params": [], "id": 1 }

      这个请求不需要任何参数。调用成功后,你会得到一个过滤器ID,如下所示:

      json { "jsonrpc": "2.0", "id": 1, "result": "0x1" // 这是过滤器ID }

      使用这个过滤器ID,你可以定期调用 eth_getFilterChanges 方法来检索自上次检查以来加入待处理池的新交易哈希:

      json { "jsonrpc": "2.0", "method": "eth_getFilterChanges", "params": ["0x1"], // 这里的 "0x1" 是之前创建的过滤器ID "id": 1 }

      这将返回一个数组,包含了所有新的待处理交易的哈希:

      json { "jsonrpc": "2.0", "id": 1, "result": [ "0x...哈希1...", "0x...哈希2...", // ...更多交易哈希... ] }

      请注意,由于以太坊节点可能会处理大量的交易,所以使用 eth_newPendingTransactionFilter 可能会导致大量的数据。此外,由于节点间的数据传播延迟,一个交易可能会在不同的节点上不同的时间被视为是 "待处理" 的。因此,使用这个过滤器时,客户端需要准备好处理潜在的大量数据,并且理解这些数据可能并不总是完全同步的。

    1. watchContractEvent

      eth_newfilter

      eth_newFilter 是一个 JSON-RPC 调用,用于在以太坊网络上创建一个新的过滤器(filter)。这个过滤器可以用来监听特定条件下的日志事件(log events),这些日志事件是智能合约在执行操作时发出的。当你想要跟踪智能合约的活动,比如特定函数的调用或者特定事件的触发时,这个功能非常有用。

      当你调用 eth_newFilter 时,你可以指定一系列的参数来定义过滤器的行为:

      • fromBlock: 开始搜索的区块号(block number)。也可以是 "earliest"(表示最早的区块),"latest"(表示最新的区块),或 "pending"(表示尚未挖出的区块)。
      • toBlock: 结束搜索的区块号。同样可以使用 "earliest"、"latest" 或 "pending"。
      • address: 一个地址或一组地址。这些地址是智能合约的地址,你只对这些特定合约发出的日志感兴趣。
      • topics: 事件的主题数组。每个事件都有一个主题列表,第一个主题是事件的签名的哈希值,后面的主题是事件日志参数的哈希值。通过指定主题,你可以进一步筛选感兴趣的事件。

      创建过滤器后,它会返回一个过滤器ID。你可以使用这个ID来调用 eth_getFilterChangeseth_getFilterLogs,这样就可以获取自过滤器创建以来发生的或所有匹配过滤器条件的日志事件。

      示例 JSON-RPC 请求创建一个新的过滤器可能如下所示:

      json { "jsonrpc": "2.0", "method": "eth_newFilter", "params": [{ "fromBlock": "0x1", "toBlock": "latest", "address": "0x8888f1f195afa192cfee860698584c030f4c9db1", "topics": [ "0x0000000000000000000000000000000000000000000000000000000012345678" ] }], "id": 1 }

      在这个请求中,我们创建了一个从区块1到最新区块的过滤器,只监听地址为 "0x8888..." 的智能合约,并且只对主题 "0x0000..." 的事件感兴趣。

      请注意,由于以太坊网络的匿名和去中心化特性,任何人都可以创建过滤器并监听事件。这是智能合约透明性的一个重要方面,但也意味着合约的设计者需要注意不要通过事件泄露敏感信息。

    1. switchChain

      没搞懂内部是如何更新的 packages/core/src/actions/switchChain.ts

    1. react

      这个插件配合wagmi cli工具可以生成合约api, 对应的react hook方法

  3. golang.halfiisland.com golang.halfiisland.com
    1. db.Model(&jack).Association("Houses").Unscoped().Delete(&houses)

    2. Association

    3. db.Model(&mit).Association("Persons").Replace(newPerson)

      学校是引用结构体,人员是被引用结构体

    4. // SELECT * FROM `people` WHERE name = 'jack' ORDER BY `people`.`id` LIMIT 1 db.Where("name = ?", "jack").First(&jack) // INSERT INTO `moms` (`name`) VALUES ('lili') db.Create(&lili) // INSERT INTO `moms` (`name`,`id`) VALUES ('lili',2) ON DUPLICATE KEY UPDATE `id`=`id` // UPDATE `people` SET `mom_id`=2 WHERE `id` = 1 db.Model(&jack).Association("Mom").Replace(&lili)

    5. 比如关联查找一个人的母亲,Association的参数就是Mom,也就是Person.Mom字段名

    6. Unscope

    7. // UPDATE `person` SET `name`='jojo',`address`='poland' WHERE `id` = 2 db.Model(p).Updates(Person{Name: "jojo", Address: "poland"}) // UPDATE `person` SET `address`='poland',`name`='jojo' WHERE `id` = 2 db.Model(p).Updates(map[string]any{"name": "jojo", "address": "poland"})

    8. db.Clauses(clause.Locking{Strength: "SHARE", Options: "NOWAIT"}).Find(&ps)

    9. &count

    10. 或者也可以我们手动来操作,通过Migrator方法访问Migrator接口

  4. golang.halfiisland.com golang.halfiisland.com
    1. // 发送消息到指定频道 redisClient.Publish("channel", "message") // 订阅指定频道 redisClient.Subscribe("channel") // 查看订阅状态 redisClient.PubSubNumSub("channel")

    2. redisClient.ZRange("ss", 1, 2)

    3. redisClient.ZRangeByScore("ss", redis.ZRangeBy{ Min: "1", Max: "2", Offset: 0, Count: 1, })

    4. // 删除指定元素 redisClient.LRem("list", 0, "a") // 删除指定范围的元素 redisClient.LTrim("list", 0, 1) // 保留指定范围的元素 redisClient.LTrim("list", 0, 1)

    5. // 左边添加 redisClient.LPush("list", "a", "b", "c", "d", "e") // 右边添加 redisClient.RPush("list", "g", "i", "a") // 在参考值前面插入值 redisClient.LInsertBefore("list", "a", "aa") // 在参考值后面插入值 redisClient.LInsertAfter("list", "a", "gg") // 设置指定下标的元素的值 redisClient.LSet("list", 0, "head")

    6. redisClient.Set("age", "1", 0) // 自增 redisClient.Incr("age") fmt.Println(redisClient.Get("age").Val()) // 自减 redisClient.Decr("age") fmt.Println(redisClient.Get("age").Val())

    7. redisClient.Set("token", "abcefghijklmn", 0)

    8. fmt.Println(redisClient.Scan(0, "", 4))

  5. Dec 2023
  6. golang.halfiisland.com golang.halfiisland.com
    1. 完全相等

      reflect.DeepEqual 与javascript的深比较还是存在区别的

    2. Person

    3. person.Interface()

    4. rType := reflect.TypeOf(new(Person)).Elem()

    5. Person

    6. rType := reflect.TypeOf(new(Person)).Elem()

    7. Unsaf

    8. fmt.Println(rType.Elem().Kind())

      值类型

    9. fmt.Println(rType.Key().Kind())

      键类型

    1. 路由器状态

    2. routerLinkActive

    3. 它充当占位符,用于在模板中标记出路由器应该显示把该组件显示在那个出口的位置。

      RouterOutlet

    1. providers 和 viewProviders 的差异
    2. providers 和 viewProviders 对服务可见性的影响有何差异,以下各节将逐步构建一个 现场演练 / 下载范例 并在代码和逻辑树中比较 providers 和 viewProviders 的作用。

    1. <ng-template ngFor let-hero [ngForOf]="heroes" let-i="index" let-odd="odd" [ngForTrackBy]="trackById">

    2. 结构型指令简写形式

      哪些指令可简写,简写成什么样

    1. 将 ngNonBindable 应用于元素将停止对该元素的子元素的绑定。但是,ngNonBindable 仍然允许指令在应用 ngNonBindable 的元素上工作。在以下示例中,appHighlight 指令仍处于活跃状态,但 Angular 不会对表达式 {{ 1 + 1 }} 求值。

      作用于内部,而不影响同级及上级

    2. 绑定到第二个属性

    1. *ngSwitchCase="'stout'"

      注意这里还有个引号

    2. Angular 的 <ng-container> 是一个分组元素,它不会干扰样式或布局,因为 Angular 不会将其放置在 DOM 中

      类似react Fragement

    3. 在简写表达式中,将 trackBy 设置为 trackByItems() 方法
    1. ngFor let-hero let-i="index" [ngForOf]="heroes"

      需要确认下这个是不是固定写法

    1. <app-sizer [(size)]="fontSizePx"></app-sizer>

      等价写法

      html <app-sizer [size]="fontSizePx" (sizeChange)="fontSizePx=$event"></app-sizer>

    2. 因为没有任何原生 HTML 元素遵循了 x 值和 xChange 事件的命名模式,所以与表单元素进行双向绑定需要使用 NgModel

      怎么理解

  7. golang.halfiisland.com golang.halfiisland.com
    1. target必须是指向error的指针,由于在创建结构体时返回的是结构体指针,所以error实际上*TimeError类型的,那么target就必须是**TimeError类型的

      很绕

  8. golang.halfiisland.com golang.halfiisland.com
    1. 也可以如下,不管返回值是否命名,优先级最高的永远都是return关键字后跟随的值

      不理解

  9. golang.halfiisland.com golang.halfiisland.com
    1. bytes = append(bytes, "that is a int"...)

      在 Go 语言中,... 有两个主要的用途,一个是在函数定义中声明可变参数(variadic function),另一个是在调用函数时展开切片。在你提供的代码示例中,... 是用来展开切片的。

      这段代码:

      go bytes = append(bytes, "that is a int"...)

      中的 ... 表示将字符串 "that is a int" 转换为字节切片后,将该字节切片中的每个元素作为独立的参数传递给 append 函数。这是因为 append 函数的第二个参数及以后的参数是可变参数,意味着你可以传递任意数量的参数,只要它们是与切片中元素类型相同的类型。

      不使用 ... 的话,你就会将整个切片作为一个单独的参数传递给 append 函数,这将导致编译错误,因为 append 期望的是单独的元素,而不是整个切片。

      这里是一个简单的例子来说明它是如何工作的:

      ```go slice := []int{1, 2, 3} slice = append(slice, 4, 5, 6) // 直接追加多个元素

      // 如果你有另一个切片,想要追加其所有元素到 slice,你需要使用 ... anotherSlice := []int{7, 8, 9} slice = append(slice, anotherSlice...) // 展开 anotherSlice 并追加其元素 ```

      在你的代码中,"that is a int" 首先被转换为一个字节切片,然后 ... 将其展开,append 函数接收到的是多个字节而不是一个切片。这样,原始的 bytes 切片就被扩展了,包含了新的字符串的字节表示。最后,扩展后的字节切片被转换回字符串并赋值给 str 变量。

  10. golang.halfiisland.com golang.halfiisland.com
    1. 但是有一种情况除外,那就是在赋值旧变量的同时声明一个新的变量,比如

      常量也能赋值哇

    1. Go语言程序员推荐使用 驼峰式 命名,当名字由几个单词组成时优先使用大小写分隔,而不是优先用下划线分隔

      命名习惯

    1. 如果你想要相邻的几个case都执行同一逻辑的话,需要自己显式地写上一个fallthrough语句来覆盖这种默认行为。不过fallthrough语句在一般的程序中很少用到。

      fallthrough语句

    1. 而在表达式 x+y 中,可在 + 后换行,不能在 + 前换行

      golang 换行符位置有限制

    1. [Property in keyof Type]: Type[Property] extends { pii: true } ? true : false;

      层次感很强

    1. 你只能在索引时使用类型,这意味着你不能使用 const 来进行变量引用

      type 与 const 区别